Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2016-02-04 06:02:49 -0500
committerEike Stepper2016-02-04 06:02:49 -0500
commite0c570e47aaa4e1dbbf4b818161ca3a9a310adde (patch)
tree8f9f3f898c442cf6670f97339d5ab237b0c64d25
parent45b55081f4200d675e18ec5cbd4a120b1b52bfe4 (diff)
downloadcdo-committers/estepper/unit-manager-squashed.tar.gz
cdo-committers/estepper/unit-manager-squashed.tar.xz
cdo-committers/estepper/unit-manager-squashed.zip
[486458] Provide support for optimized loading and notifying of object units committers/estepper/unit-manager-squashed
https://bugs.eclipse.org/bugs/show_bug.cgi?id=486458
-rw-r--r--features/org.eclipse.net4j.db.mysql-feature/feature.xml2
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/id/CDOIDUtil.java8
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java31
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionUtil.java37
-rw-r--r--plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/META-INF/MANIFEST.MF2
-rw-r--r--plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml12
-rw-r--r--plugins/org.eclipse.emf.cdo.examples.master/META-INF/MANIFEST.MF2
-rw-r--r--plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml12
-rw-r--r--plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java77
-rw-r--r--plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/UnitRequest.java74
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java3
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingUnitSupport.java30
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping3.java22
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMappingUnitSupport.java34
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java67
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java17
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java104
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java8
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/UUIDHandler.java1
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java16
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java10
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java129
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java515
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java372
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java2
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java9
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/UnitMappingTable.java317
-rw-r--r--plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateRawCommitContext.java7
-rw-r--r--plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java3
-rw-r--r--plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/UnitIndication.java128
-rw-r--r--plugins/org.eclipse.emf.cdo.server.product/CDOServer.launch2
-rw-r--r--plugins/org.eclipse.emf.cdo.server.product/META-INF/MANIFEST.MF2
-rw-r--r--plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml12
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java73
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java6
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java15
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java2
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/UnitManager.java734
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java82
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedClientSessionProtocol.java5
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IRepository.java10
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java22
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IUnit.java33
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IUnitManager.java35
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalCommitContext.java5
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java15
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalUnitManager.java34
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java16
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/Store.java7
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java22
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/CDO AllTests (H2 audit).launch2
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/MysqlConfig.java8
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java2
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOStaleReferencePolicyTest.java (renamed from plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOStaleReferencePolicyTests.java)2
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java5
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/UnitManagerMain.java291
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_329254_Test.java6
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_340709_Test.java3
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_349793_Test.java5
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_423699_Test.java11
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_427773_Test.java2
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485961_Test.java3
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458_Test.java410
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458a_Test.java348
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458b_Test.java381
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458c_Test.java256
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java14
-rw-r--r--plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/compare/CDOCompareEditorUtil.java4
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java9
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOUnit.java39
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOUnitManager.java54
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java5
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java16
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java2
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java20
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java409
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOMergingConflictResolver.java3
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java6
-rw-r--r--plugins/org.eclipse.net4j.db.h2/H2 Browser.launch13
-rw-r--r--plugins/org.eclipse.net4j.db.mysql/META-INF/MANIFEST.MF6
-rw-r--r--plugins/org.eclipse.net4j.db.mysql/src/org/eclipse/net4j/db/mysql/MYSQLAdapter.java77
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/BatchedStatement.java28
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBUtil.java9
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBAdapter.java5
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/BatchedStatementImpl.java134
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java4
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBPreparedStatement.java2
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBAdapter.java8
-rw-r--r--plugins/org.eclipse.net4j/src/org/eclipse/net4j/buffer/BufferInputStream.java10
89 files changed, 5244 insertions, 551 deletions
diff --git a/features/org.eclipse.net4j.db.mysql-feature/feature.xml b/features/org.eclipse.net4j.db.mysql-feature/feature.xml
index a76aadd927..41fbf937ee 100644
--- a/features/org.eclipse.net4j.db.mysql-feature/feature.xml
+++ b/features/org.eclipse.net4j.db.mysql-feature/feature.xml
@@ -12,7 +12,7 @@
<feature
id="org.eclipse.net4j.db.mysql"
label="%featureName"
- version="4.2.200.qualifier"
+ version="4.2.300.qualifier"
provider-name="%providerName"
license-feature="org.eclipse.emf.cdo.license"
license-feature-version="0.0.0">
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/id/CDOIDUtil.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/id/CDOIDUtil.java
index e4a303e7bb..c869398125 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/id/CDOIDUtil.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/id/CDOIDUtil.java
@@ -69,6 +69,14 @@ public final class CDOIDUtil
}
/**
+ * @since 4.5
+ */
+ public static <V> Map<CDOID, V> createMap(Map<? extends CDOID, ? extends V> map)
+ {
+ return new HashMap<CDOID, V>(map);
+ }
+
+ /**
* @since 4.0
*/
public static CDOIDAndVersion createIDAndVersion(CDOID id, int version)
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java
index d9196795c5..72fa700a76 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDOProtocolConstants.java
@@ -30,8 +30,9 @@ public interface CDOProtocolConstants
* @since 4.2
* @noreference This field is not intended to be referenced by clients.
*/
- public static final int PROTOCOL_VERSION = 28; // SIGNAL_RESET_TRANSACTION
+ public static final int PROTOCOL_VERSION = 29; // SIGNAL_UNIT
+ // public static final int PROTOCOL_VERSION = 28; // SIGNAL_RESET_TRANSACTION
// public static final int PROTOCOL_VERSION = 27; // SIGNAL_OPENED_SESSION
// public static final int PROTOCOL_VERSION = 26; // Add prefetch depth in LockStateRequest/Indication
// public static final int PROTOCOL_VERSION = 25; // OpenSessionResponse.repositoryAuthenticating
@@ -312,6 +313,11 @@ public interface CDOProtocolConstants
*/
public static final short SIGNAL_RESET_TRANSACTION = 61;
+ /**
+ * @since 4.5
+ */
+ public static final short SIGNAL_UNIT = 62;
+
// //////////////////////////////////////////////////////////////////////
// Session Refresh
@@ -470,4 +476,27 @@ public interface CDOProtocolConstants
* @since 4.3
*/
public static final byte REVISION_DOES_NOT_EXIST = -1;
+
+ // //////////////////////////////////////////////////////////////////////
+ // Units
+
+ /**
+ * @since 4.5
+ */
+ public static final byte UNIT_CHECK = 0;
+
+ /**
+ * @since 4.5
+ */
+ public static final byte UNIT_CREATE = 1;
+
+ /**
+ * @since 4.5
+ */
+ public static final byte UNIT_OPEN = 2;
+
+ /**
+ * @since 4.5
+ */
+ public static final byte UNIT_CLOSE = 3;
}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionUtil.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionUtil.java
index 5cccda0ea2..88b674503b 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionUtil.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevisionUtil.java
@@ -323,20 +323,40 @@ public final class CDORevisionUtil
return true;
}
- InternalCDORevision parent = getParentRevision(child, provider);
+ CDORevision parent = getParentRevision(child, provider);
if (parent != null)
{
- return isContained(parent, container, provider);
+ return isContained((InternalCDORevision)parent, container, provider);
}
return false;
}
- private static InternalCDORevision getParentRevision(InternalCDORevision revision, CDORevisionProvider provider)
+ /**
+ * @since 4.5
+ */
+ public static void handleParentRevisions(CDORevision revision, CDORevisionProvider provider,
+ CDORevisionHandler handler)
+ {
+ CDORevision parentRevision = getParentRevision(revision, provider);
+ if (parentRevision != null)
+ {
+ if (handler.handleRevision(parentRevision))
+ {
+ handleParentRevisions(parentRevision, provider, handler);
+ }
+ }
+ }
+
+ /**
+ * @since 4.5
+ */
+ public static CDORevision getParentRevision(CDORevision revision, CDORevisionProvider provider)
{
CDOID parentID;
+ CDORevisionData data = revision.data();
- Object containerID = revision.getContainerID();
+ Object containerID = data.getContainerID();
if (containerID instanceof CDOWithID)
{
parentID = ((CDOWithID)containerID).cdoID();
@@ -348,7 +368,7 @@ public final class CDORevisionUtil
if (CDOIDUtil.isNull(parentID))
{
- parentID = revision.getResourceID();
+ parentID = data.getResourceID();
if (CDOIDUtil.isNull(parentID))
{
return null;
@@ -361,10 +381,13 @@ public final class CDORevisionUtil
}
}
- return (InternalCDORevision)provider.getRevision(parentID);
+ return provider.getRevision(parentID);
}
/**
+ * @since 4.5
+ */
+ /**
* @since 4.4
*/
public static List<CDORevision> getChildRevisions(CDOID container, CDORevisionProvider provider)
@@ -485,7 +508,7 @@ public final class CDORevisionUtil
}
else
{
- container = getParentRevision(revision, provider);
+ container = (InternalCDORevision)getParentRevision(revision, provider);
}
if (container != null)
diff --git a/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/META-INF/MANIFEST.MF
index 3ad1ff962e..b4cb289830 100644
--- a/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/META-INF/MANIFEST.MF
@@ -1,7 +1,7 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.eclipse.emf.cdo.examples.master;singleton:=true
-Bundle-Version: 4.1.200.qualifier
+Bundle-Version: 4.1.300.qualifier
Bundle-Name: %pluginName
Bundle-Vendor: %providerName
Bundle-ActivationPolicy: lazy
diff --git a/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml b/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
index 0e00773d0c..a5fe276c16 100644
--- a/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
+++ b/plugins/org.eclipse.emf.cdo.examples.installer/examples/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
@@ -17,6 +17,7 @@
<property name="overrideUUID" value=""/>
<property name="supportingAudits" value="true"/>
<property name="supportingBranches" value="true"/>
+ <property name="supportingUnits" value="false"/>
<property name="ensureReferentialIntegrity" value="false"/>
<property name="allowInterruptRunningQueries" value="true"/>
<property name="idGenerationLocation" value="CLIENT"/> <!-- Possible values: STORE | CLIENT -->
@@ -52,6 +53,7 @@
<mappingStrategy type="horizontal"> <!-- callout -->
<property name="qualifiedNames" value="true"/>
+ <property name="withRanges" value="false"/>
<!--
Per default, the objectTypeCache is in-memory and contains
@@ -59,17 +61,15 @@
uncomment the following line and set the desired size.
The cache can be disabled by setting a size of 0.
-->
-
<!-- Optional:
<property name="objectTypeCacheSize" value="100000"/>
-->
-
</mappingStrategy>
<dbAdapter name="h2"/>
<dataSource class="org.h2.jdbcx.JdbcDataSource"
- URL="jdbc:h2:database/repo1"/>
-
+ URL="jdbc:h2:/develop/cdo-master/h2/big"/>
+
<!-- Example:
<dbAdapter name="derby-embedded"/>
<dataSource class="org.apache.derby.jdbc.EmbeddedDataSource"
@@ -87,8 +87,8 @@
<!-- Example:
<dbAdapter name="mysql"/>
<dataSource class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
- url="jdbc:mysql://localhost/repo1"
- user="sa"/>
+ url="jdbc:mysql://localhost/big"
+ user="test" password="0000"/>
-->
<!-- Example:
diff --git a/plugins/org.eclipse.emf.cdo.examples.master/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.examples.master/META-INF/MANIFEST.MF
index 3ad1ff962e..b4cb289830 100644
--- a/plugins/org.eclipse.emf.cdo.examples.master/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.cdo.examples.master/META-INF/MANIFEST.MF
@@ -1,7 +1,7 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.eclipse.emf.cdo.examples.master;singleton:=true
-Bundle-Version: 4.1.200.qualifier
+Bundle-Version: 4.1.300.qualifier
Bundle-Name: %pluginName
Bundle-Vendor: %providerName
Bundle-ActivationPolicy: lazy
diff --git a/plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml b/plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
index 0e00773d0c..a5fe276c16 100644
--- a/plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
+++ b/plugins/org.eclipse.emf.cdo.examples.master/config/cdo-server.xml
@@ -17,6 +17,7 @@
<property name="overrideUUID" value=""/>
<property name="supportingAudits" value="true"/>
<property name="supportingBranches" value="true"/>
+ <property name="supportingUnits" value="false"/>
<property name="ensureReferentialIntegrity" value="false"/>
<property name="allowInterruptRunningQueries" value="true"/>
<property name="idGenerationLocation" value="CLIENT"/> <!-- Possible values: STORE | CLIENT -->
@@ -52,6 +53,7 @@
<mappingStrategy type="horizontal"> <!-- callout -->
<property name="qualifiedNames" value="true"/>
+ <property name="withRanges" value="false"/>
<!--
Per default, the objectTypeCache is in-memory and contains
@@ -59,17 +61,15 @@
uncomment the following line and set the desired size.
The cache can be disabled by setting a size of 0.
-->
-
<!-- Optional:
<property name="objectTypeCacheSize" value="100000"/>
-->
-
</mappingStrategy>
<dbAdapter name="h2"/>
<dataSource class="org.h2.jdbcx.JdbcDataSource"
- URL="jdbc:h2:database/repo1"/>
-
+ URL="jdbc:h2:/develop/cdo-master/h2/big"/>
+
<!-- Example:
<dbAdapter name="derby-embedded"/>
<dataSource class="org.apache.derby.jdbc.EmbeddedDataSource"
@@ -87,8 +87,8 @@
<!-- Example:
<dbAdapter name="mysql"/>
<dataSource class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
- url="jdbc:mysql://localhost/repo1"
- user="sa"/>
+ url="jdbc:mysql://localhost/big"
+ user="test" password="0000"/>
-->
<!-- Example:
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java
index 2e6f609394..f58ae8f414 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java
@@ -503,6 +503,47 @@ public class CDOClientProtocol extends AuthenticatingSignalProtocol<CDOSessionIm
return send(new LoadMergeDataRequest(this, targetInfo, sourceInfo, targetBaseInfo, sourceBaseInfo));
}
+ @Deprecated
+ public CDOLockState[] getLockStates(int viewID, Collection<CDOID> ids)
+ {
+ return getLockStates(viewID, ids, CDOLockState.DEPTH_NONE);
+ }
+
+ public CDOLockState[] getLockStates(int viewID, Collection<CDOID> ids, int depth)
+ {
+ return send(new LockStateRequest(this, viewID, ids, depth));
+ }
+
+ public void enableLockNotifications(int viewID, boolean on)
+ {
+ send(new EnableLockNotificationRequest(this, viewID, on));
+ }
+
+ public void setLockNotificationMode(LockNotificationMode mode)
+ {
+ send(new SetLockNotificationModeRequest(this, mode));
+ }
+
+ public Map<CDORevision, CDOPermission> loadPermissions(InternalCDORevision[] revisions)
+ {
+ return send(new LoadPermissionsRequest(this, revisions));
+ }
+
+ public void requestChangeCredentials()
+ {
+ send(new ChangeCredentialsRequest(this, CredentialsUpdateOperation.CHANGE_PASSWORD, null), new Monitor());
+ }
+
+ public void requestResetCredentials(String userID)
+ {
+ send(new ChangeCredentialsRequest(this, CredentialsUpdateOperation.RESET_PASSWORD, userID), new Monitor());
+ }
+
+ public boolean requestUnit(int viewID, CDOID rootID, byte opcode, CDORevisionHandler revisionHandler)
+ {
+ return send(new UnitRequest(this, viewID, rootID, opcode, revisionHandler));
+ }
+
@Override
protected SignalReactor createSignalReactor(short signalID)
{
@@ -600,40 +641,4 @@ public class CDOClientProtocol extends AuthenticatingSignalProtocol<CDOSessionIm
REVISION_LOADING.stop(request);
}
}
-
- @Deprecated
- public CDOLockState[] getLockStates(int viewID, Collection<CDOID> ids)
- {
- return getLockStates(viewID, ids, CDOLockState.DEPTH_NONE);
- }
-
- public CDOLockState[] getLockStates(int viewID, Collection<CDOID> ids, int depth)
- {
- return send(new LockStateRequest(this, viewID, ids, depth));
- }
-
- public void enableLockNotifications(int viewID, boolean on)
- {
- send(new EnableLockNotificationRequest(this, viewID, on));
- }
-
- public void setLockNotificationMode(LockNotificationMode mode)
- {
- send(new SetLockNotificationModeRequest(this, mode));
- }
-
- public Map<CDORevision, CDOPermission> loadPermissions(InternalCDORevision[] revisions)
- {
- return send(new LoadPermissionsRequest(this, revisions));
- }
-
- public void requestChangeCredentials()
- {
- send(new ChangeCredentialsRequest(this, CredentialsUpdateOperation.CHANGE_PASSWORD, null), new Monitor());
- }
-
- public void requestResetCredentials(String userID)
- {
- send(new ChangeCredentialsRequest(this, CredentialsUpdateOperation.RESET_PASSWORD, userID), new Monitor());
- }
}
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/UnitRequest.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/UnitRequest.java
new file mode 100644
index 0000000000..01e23d3559
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/UnitRequest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.internal.net4j.protocol;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import java.io.IOException;
+
+/**
+ * @author Eike Stepper
+ */
+public class UnitRequest extends CDOClientRequestWithMonitoring<Boolean>
+{
+ private int viewID;
+
+ private CDOID rootID;
+
+ private byte opcode;
+
+ private CDORevisionHandler revisionHandler;
+
+ public UnitRequest(CDOClientProtocol protocol, int viewID, CDOID rootID, byte opcode,
+ CDORevisionHandler revisionHandler)
+ {
+ super(protocol, CDOProtocolConstants.SIGNAL_UNIT);
+ this.viewID = viewID;
+ this.rootID = rootID;
+ this.opcode = opcode;
+ this.revisionHandler = revisionHandler;
+ }
+
+ @Override
+ protected void requesting(CDODataOutput out, OMMonitor monitor) throws IOException
+ {
+ out.writeInt(viewID);
+ out.writeCDOID(rootID);
+ out.writeByte(opcode);
+ }
+
+ @Override
+ protected Boolean confirming(CDODataInput in, OMMonitor monitor) throws IOException
+ {
+ if (opcode == CDOProtocolConstants.UNIT_CREATE || opcode == CDOProtocolConstants.UNIT_OPEN)
+ {
+ for (;;)
+ {
+ CDORevision revision = in.readCDORevision();
+ if (revision == null)
+ {
+ break;
+ }
+
+ revisionHandler.handleRevision(revision);
+ }
+ }
+
+ return in.readBoolean();
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java
index 4b80d68f95..78b9747bcd 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java
@@ -11,6 +11,7 @@
package org.eclipse.emf.cdo.server.db;
import org.eclipse.emf.cdo.server.IStoreAccessor;
+import org.eclipse.emf.cdo.server.IStoreAccessor.UnitSupport;
import org.eclipse.net4j.db.IDBConnection;
@@ -23,7 +24,7 @@ import java.sql.Connection;
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
*/
-public interface IDBStoreAccessor extends IStoreAccessor.Raw
+public interface IDBStoreAccessor extends IStoreAccessor.Raw, UnitSupport
{
public IDBStore getStore();
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingUnitSupport.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingUnitSupport.java
new file mode 100644
index 0000000000..65e8e77d33
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingUnitSupport.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.db.mapping;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+
+import java.sql.SQLException;
+
+/**
+ * An extension interface for {@link IClassMapping class mappings} that support <i>units</i>.
+ *
+ * @author Eike Stepper
+ * @since 4.4
+ */
+public interface IClassMappingUnitSupport extends IClassMapping
+{
+ public void readUnitRevisions(IDBStoreAccessor accessor, CDOBranchPoint branchPoint, CDOID rootID,
+ CDORevisionHandler revisionHandler) throws SQLException;
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping3.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping3.java
new file mode 100644
index 0000000000..8fc37c5a4e
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping3.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.db.mapping;
+
+/**
+ * Extension interface to {@link IListMapping2}.
+ *
+ * @author Eike Stepper
+ * @since 4.4
+ */
+public interface IListMapping3 extends IListMapping2
+{
+ public void setClassMapping(IClassMapping classMapping);
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMappingUnitSupport.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMappingUnitSupport.java
new file mode 100644
index 0000000000..c97e0f363b
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMappingUnitSupport.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.db.mapping;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+
+import org.eclipse.net4j.util.collection.MoveableList;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * Interface to complement {@link IListMapping} in order to provide unit support.
+ *
+ * @author Eike Stepper
+ * @since 4.4
+ */
+public interface IListMappingUnitSupport extends IListMapping
+{
+ public ResultSet queryUnitEntries(IDBStoreAccessor accessor, IIDHandler idHandler, CDOID rootID) throws SQLException;
+
+ public void readUnitEntries(ResultSet resultSet, IIDHandler idHandler, CDOID id, MoveableList<Object> list)
+ throws SQLException;
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java
index 6b42da68b6..efc86e0dc7 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java
@@ -35,13 +35,13 @@ public class CDODBSchema
public static final IDBTable PROPERTIES = INSTANCE.addTable("cdo_properties"); //$NON-NLS-1$
public static final IDBField PROPERTIES_NAME = //
- PROPERTIES.addField("name", DBType.VARCHAR, 255, true); //$NON-NLS-1$
+ PROPERTIES.addField("name", DBType.VARCHAR, 255, true); //$NON-NLS-1$
public static final IDBField PROPERTIES_VALUE = //
- PROPERTIES.addField("value", DBType.LONGVARCHAR); //$NON-NLS-1$
+ PROPERTIES.addField("value", DBType.LONGVARCHAR); //$NON-NLS-1$
public static final IDBIndex INDEX_PROPERTIES_PK = //
- PROPERTIES.addIndex(IDBIndex.Type.PRIMARY_KEY, PROPERTIES_NAME);
+ PROPERTIES.addIndex(IDBIndex.Type.PRIMARY_KEY, PROPERTIES_NAME);
public static final String SQL_DELETE_PROPERTIES = "DELETE FROM " + PROPERTIES + " WHERE " + PROPERTIES_NAME + "=?"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
@@ -60,19 +60,19 @@ public class CDODBSchema
public static final IDBTable PACKAGE_UNITS = INSTANCE.addTable("cdo_package_units"); //$NON-NLS-1$
public static final IDBField PACKAGE_UNITS_ID = //
- PACKAGE_UNITS.addField("id", DBType.VARCHAR, 255, true); //$NON-NLS-1$
+ PACKAGE_UNITS.addField("id", DBType.VARCHAR, 255, true); //$NON-NLS-1$
public static final IDBField PACKAGE_UNITS_ORIGINAL_TYPE = //
- PACKAGE_UNITS.addField("original_type", DBType.INTEGER); //$NON-NLS-1$
+ PACKAGE_UNITS.addField("original_type", DBType.INTEGER); //$NON-NLS-1$
public static final IDBField PACKAGE_UNITS_TIME_STAMP = //
- PACKAGE_UNITS.addField("time_stamp", DBType.BIGINT); //$NON-NLS-1$
+ PACKAGE_UNITS.addField("time_stamp", DBType.BIGINT); //$NON-NLS-1$
public static final IDBField PACKAGE_UNITS_PACKAGE_DATA = //
- PACKAGE_UNITS.addField("package_data", DBType.BLOB); //$NON-NLS-1$
+ PACKAGE_UNITS.addField("package_data", DBType.BLOB); //$NON-NLS-1$
public static final IDBIndex INDEX_PACKAGE_UNITS_PK = //
- PACKAGE_UNITS.addIndex(IDBIndex.Type.PRIMARY_KEY, PACKAGE_UNITS_ID);
+ PACKAGE_UNITS.addIndex(IDBIndex.Type.PRIMARY_KEY, PACKAGE_UNITS_ID);
/**
* DBTable cdo_packages
@@ -80,22 +80,22 @@ public class CDODBSchema
public static final IDBTable PACKAGE_INFOS = INSTANCE.addTable("cdo_package_infos"); //$NON-NLS-1$
public static final IDBField PACKAGE_INFOS_URI = //
- PACKAGE_INFOS.addField("uri", DBType.VARCHAR, 255, true); //$NON-NLS-1$
+ PACKAGE_INFOS.addField("uri", DBType.VARCHAR, 255, true); //$NON-NLS-1$
public static final IDBField PACKAGE_INFOS_PARENT = //
- PACKAGE_INFOS.addField("parent", DBType.VARCHAR, 255); //$NON-NLS-1$
+ PACKAGE_INFOS.addField("parent", DBType.VARCHAR, 255); //$NON-NLS-1$
public static final IDBField PACKAGE_INFOS_UNIT = //
- PACKAGE_INFOS.addField("unit", DBType.VARCHAR, 255); //$NON-NLS-1$
+ PACKAGE_INFOS.addField("unit", DBType.VARCHAR, 255); //$NON-NLS-1$
public static final IDBIndex INDEX_PACKAGE_INFOS_PK = //
- PACKAGE_INFOS.addIndex(IDBIndex.Type.PRIMARY_KEY, PACKAGE_INFOS_URI);
+ PACKAGE_INFOS.addIndex(IDBIndex.Type.PRIMARY_KEY, PACKAGE_INFOS_URI);
public static final IDBIndex INDEX_PACKAGE_INFOS_PARENT = //
- PACKAGE_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, PACKAGE_INFOS_PARENT);
+ PACKAGE_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, PACKAGE_INFOS_PARENT);
public static final IDBIndex INDEX_PACKAGE_INFOS_UNIT = //
- PACKAGE_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, PACKAGE_INFOS_UNIT);
+ PACKAGE_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, PACKAGE_INFOS_UNIT);
/**
* DBTable cdo_branches
@@ -103,19 +103,19 @@ public class CDODBSchema
public static final IDBTable BRANCHES = INSTANCE.addTable("cdo_branches"); //$NON-NLS-1$
public static final IDBField BRANCHES_ID = //
- BRANCHES.addField("id", DBType.INTEGER, true); //$NON-NLS-1$
+ BRANCHES.addField("id", DBType.INTEGER, true); //$NON-NLS-1$
public static final IDBField BRANCHES_NAME = //
- BRANCHES.addField("name", DBType.VARCHAR); //$NON-NLS-1$
+ BRANCHES.addField("name", DBType.VARCHAR); //$NON-NLS-1$
public static final IDBField BRANCHES_BASE_BRANCH_ID = //
- BRANCHES.addField("base_id", DBType.INTEGER); //$NON-NLS-1$
+ BRANCHES.addField("base_id", DBType.INTEGER); //$NON-NLS-1$
public static final IDBField BRANCHES_BASE_TIMESTAMP = //
- BRANCHES.addField("base_time", DBType.BIGINT); //$NON-NLS-1$
+ BRANCHES.addField("base_time", DBType.BIGINT); //$NON-NLS-1$
public static final IDBIndex INDEX_BRANCHES_ID = //
- BRANCHES.addIndex(IDBIndex.Type.PRIMARY_KEY, BRANCHES_ID);
+ BRANCHES.addIndex(IDBIndex.Type.PRIMARY_KEY, BRANCHES_ID);
public static final String SQL_CREATE_BRANCH = "INSERT INTO " + BRANCHES + " (" + BRANCHES_ID + ", " + BRANCHES_NAME //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ ", " + BRANCHES_BASE_BRANCH_ID + ", " + BRANCHES_BASE_TIMESTAMP + ") VALUES (?, ?, ?, ?)"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
@@ -139,33 +139,32 @@ public class CDODBSchema
public static final IDBTable COMMIT_INFOS = INSTANCE.addTable("cdo_commit_infos"); //$NON-NLS-1$
public static final IDBField COMMIT_INFOS_TIMESTAMP = //
- COMMIT_INFOS.addField("commit_time", DBType.BIGINT, true); //$NON-NLS-1$
+ COMMIT_INFOS.addField("commit_time", DBType.BIGINT, true); //$NON-NLS-1$
public static final IDBField COMMIT_INFOS_PREVIOUS_TIMESTAMP = //
- COMMIT_INFOS.addField("previous_time", DBType.BIGINT); //$NON-NLS-1$
+ COMMIT_INFOS.addField("previous_time", DBType.BIGINT); //$NON-NLS-1$
public static final IDBField COMMIT_INFOS_BRANCH = //
- COMMIT_INFOS.addField("branch_id", DBType.INTEGER); //$NON-NLS-1$
+ COMMIT_INFOS.addField("branch_id", DBType.INTEGER); //$NON-NLS-1$
public static final IDBField COMMIT_INFOS_USER = //
- COMMIT_INFOS.addField("user_id", DBType.VARCHAR); //$NON-NLS-1$
+ COMMIT_INFOS.addField("user_id", DBType.VARCHAR); //$NON-NLS-1$
public static final IDBField COMMIT_INFOS_COMMENT = //
- COMMIT_INFOS.addField("commit_comment", DBType.VARCHAR); //$NON-NLS-1$
+ COMMIT_INFOS.addField("commit_comment", DBType.VARCHAR); //$NON-NLS-1$
public static final IDBIndex INDEX_COMMIT_INFOS_PK = //
- COMMIT_INFOS.addIndex(IDBIndex.Type.PRIMARY_KEY, COMMIT_INFOS_TIMESTAMP);
+ COMMIT_INFOS.addIndex(IDBIndex.Type.PRIMARY_KEY, COMMIT_INFOS_TIMESTAMP);
public static final IDBIndex INDEX_COMMIT_INFOS_BRANCH = //
- COMMIT_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, COMMIT_INFOS_BRANCH);
+ COMMIT_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, COMMIT_INFOS_BRANCH);
public static final IDBIndex INDEX_COMMIT_INFOS_USER = //
- COMMIT_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, COMMIT_INFOS_USER);
+ COMMIT_INFOS.addIndex(IDBIndex.Type.NON_UNIQUE, COMMIT_INFOS_USER);
public static final String SQL_CREATE_COMMIT_INFO = "INSERT INTO " + COMMIT_INFOS + "(" + COMMIT_INFOS_TIMESTAMP //$NON-NLS-1$ //$NON-NLS-2$
+ ", " + COMMIT_INFOS_PREVIOUS_TIMESTAMP + ", " + COMMIT_INFOS_BRANCH + ", " + COMMIT_INFOS_USER + ", " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
- + COMMIT_INFOS_COMMENT + ") "
- + "VALUES (?, ?, ?, ?, ?)"; //$NON-NLS-1$
+ + COMMIT_INFOS_COMMENT + ") " + "VALUES (?, ?, ?, ?, ?)"; //$NON-NLS-2$
/**
* DBTable cdo_lobs
@@ -173,19 +172,19 @@ public class CDODBSchema
public static final IDBTable LOBS = INSTANCE.addTable("cdo_lobs"); //$NON-NLS-1$
public static final IDBField LOBS_ID = //
- LOBS.addField("id", DBType.VARCHAR, 64, true); //$NON-NLS-1$
+ LOBS.addField("id", DBType.VARCHAR, 64, true); //$NON-NLS-1$
public static final IDBField LOBS_SIZE = //
- LOBS.addField("lsize", DBType.BIGINT); //$NON-NLS-1$
+ LOBS.addField("lsize", DBType.BIGINT); //$NON-NLS-1$
public static final IDBField LOBS_BDATA = //
- LOBS.addField("bdata", DBType.BLOB); //$NON-NLS-1$
+ LOBS.addField("bdata", DBType.BLOB); //$NON-NLS-1$
public static final IDBField LOBS_CDATA = //
- LOBS.addField("cdata", DBType.CLOB); //$NON-NLS-1$
+ LOBS.addField("cdata", DBType.CLOB); //$NON-NLS-1$
public static final IDBIndex INDEX_LOBS_ID = //
- LOBS.addIndex(IDBIndex.Type.PRIMARY_KEY, LOBS_ID);
+ LOBS.addIndex(IDBIndex.Type.PRIMARY_KEY, LOBS_ID);
public static final String SQL_QUERY_LOBS = "SELECT 1 FROM " + CDODBSchema.LOBS + " WHERE " + CDODBSchema.LOBS_ID //$NON-NLS-1$ //$NON-NLS-2$
+ "=?"; //$NON-NLS-1$
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java
index 9efd29ccc8..48df638948 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java
@@ -32,6 +32,7 @@ import org.eclipse.emf.cdo.server.db.IMetaDataManager;
import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.IMappingConstants;
+import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.UnitMappingTable;
import org.eclipse.emf.cdo.server.internal.db.messages.Messages;
import org.eclipse.emf.cdo.spi.server.InternalRepository;
import org.eclipse.emf.cdo.spi.server.InternalSession;
@@ -115,6 +116,8 @@ public class DBStore extends Store implements IDBStore, IMappingConstants, CDOAl
private DurableLockingManager durableLockingManager = new DurableLockingManager(this);
+ private UnitMappingTable unitMappingTable;
+
private IMappingStrategy mappingStrategy;
private IDBDatabase database;
@@ -237,6 +240,11 @@ public class DBStore extends Store implements IDBStore, IMappingConstants, CDOAl
return durableLockingManager;
}
+ public UnitMappingTable getUnitMappingTable()
+ {
+ return unitMappingTable;
+ }
+
public Timer getConnectionKeepAliveTimer()
{
return connectionKeepAliveTimer;
@@ -640,6 +648,12 @@ public class DBStore extends Store implements IDBStore, IMappingConstants, CDOAl
LifecycleUtil.activate(durableLockingManager);
LifecycleUtil.activate(mappingStrategy);
+ if (repository.isSupportingUnits())
+ {
+ unitMappingTable = new UnitMappingTable(mappingStrategy);
+ unitMappingTable.activate();
+ }
+
setRevisionTemporality(mappingStrategy.hasAuditSupport() ? RevisionTemporality.AUDITING : RevisionTemporality.NONE);
setRevisionParallelism(
mappingStrategy.hasBranchingSupport() ? RevisionParallelism.BRANCHING : RevisionParallelism.NONE);
@@ -659,6 +673,7 @@ public class DBStore extends Store implements IDBStore, IMappingConstants, CDOAl
@Override
protected void doDeactivate() throws Exception
{
+ LifecycleUtil.deactivate(unitMappingTable);
LifecycleUtil.deactivate(mappingStrategy);
LifecycleUtil.deactivate(durableLockingManager);
LifecycleUtil.deactivate(metaDataManager);
@@ -961,7 +976,7 @@ public class DBStore extends Store implements IDBStore, IMappingConstants, CDOAl
};
private static final SchemaMigrator[] SCHEMA_MIGRATORS = { NO_MIGRATION_NEEDED, NON_AUDIT_MIGRATION,
- LOB_SIZE_MIGRATION, NO_MIGRATION_NEEDED };
+ LOB_SIZE_MIGRATION, NO_MIGRATION_NEEDED };
static
{
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java
index 834cbca7b9..90514b8911 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java
@@ -39,6 +39,7 @@ import org.eclipse.emf.cdo.server.ISession;
import org.eclipse.emf.cdo.server.IStoreAccessor;
import org.eclipse.emf.cdo.server.IStoreAccessor.DurableLocking2;
import org.eclipse.emf.cdo.server.ITransaction;
+import org.eclipse.emf.cdo.server.IView;
import org.eclipse.emf.cdo.server.db.IDBStore;
import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
import org.eclipse.emf.cdo.server.db.IIDHandler;
@@ -49,6 +50,7 @@ import org.eclipse.emf.cdo.server.db.mapping.IClassMappingDeltaSupport;
import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.AbstractHorizontalClassMapping;
+import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.UnitMappingTable;
import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager;
import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager.BranchLoader3;
@@ -63,8 +65,11 @@ import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
import org.eclipse.emf.cdo.spi.server.InternalCommitContext;
import org.eclipse.emf.cdo.spi.server.InternalRepository;
+import org.eclipse.emf.cdo.spi.server.InternalUnitManager;
+import org.eclipse.emf.cdo.spi.server.InternalUnitManager.InternalObjectAttacher;
import org.eclipse.emf.cdo.spi.server.StoreAccessor;
+import org.eclipse.net4j.db.BatchedStatement;
import org.eclipse.net4j.db.DBException;
import org.eclipse.net4j.db.DBUtil;
import org.eclipse.net4j.db.IDBConnection;
@@ -118,10 +123,10 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor,
private ConnectionKeepAliveTask connectionKeepAliveTask;
- private Set<CDOID> newObjects = new HashSet<CDOID>();
-
private CDOID maxID = CDOID.NULL;
+ private InternalObjectAttacher objectAttacher;
+
public DBStoreAccessor(DBStore store, ISession session) throws DBException
{
super(store, session);
@@ -133,17 +138,17 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor,
}
@Override
- public DBStore getStore()
+ public final DBStore getStore()
{
return (DBStore)super.getStore();
}
- public IDBConnection getDBConnection()
+ public final IDBConnection getDBConnection()
{
return connection;
}
- public Connection getConnection()
+ public final Connection getConnection()
{
return connection;
}
@@ -480,17 +485,17 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor,
{
super.applyIDMappings(context, monitor);
+ DBStore store = getStore();
+ IIDHandler idHandler = store.getIDHandler();
+
// Remember maxID because it may have to be adjusted if the repository is BACKUP or CLONE. See bug 325097.
boolean adjustMaxID = !context.getBranchPoint().getBranch().isLocal()
- && getStore().getRepository().getIDGenerationLocation() == IDGenerationLocation.STORE;
-
- IIDHandler idHandler = getStore().getIDHandler();
+ && store.getRepository().getIDGenerationLocation() == IDGenerationLocation.STORE;
// Remember CDOIDs of new objects. They are cleared after writeRevisions()
for (InternalCDORevision revision : context.getNewObjects())
{
CDOID id = revision.getID();
- newObjects.add(id);
if (adjustMaxID && idHandler.compare(id, maxID) > 0)
{
@@ -560,24 +565,52 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor,
}
@Override
- protected void writeRevisions(InternalCDORevision[] revisions, CDOBranch branch, OMMonitor monitor)
+ protected void writeNewObjectRevisions(InternalCommitContext context, InternalCDORevision[] newObjects,
+ CDOBranch branch, OMMonitor monitor)
+ {
+ writeRevisions(context, true, newObjects, branch, monitor);
+ }
+
+ @Override
+ protected void writeDirtyObjectRevisions(InternalCommitContext context, InternalCDORevision[] dirtyObjects,
+ CDOBranch branch, OMMonitor monitor)
+ {
+ writeRevisions(context, false, dirtyObjects, branch, monitor);
+ }
+
+ protected void writeRevisions(InternalCommitContext context, boolean attachNewObjects,
+ InternalCDORevision[] revisions, CDOBranch branch, OMMonitor monitor)
{
try
{
monitor.begin(revisions.length);
for (InternalCDORevision revision : revisions)
{
- boolean mapType = newObjects.contains(revision.getID());
- writeRevision(revision, mapType, true, monitor.fork());
+ writeRevision(revision, attachNewObjects, true, monitor.fork());
+ }
+
+ if (attachNewObjects)
+ {
+ InternalRepository repository = getStore().getRepository();
+ if (repository.isSupportingUnits())
+ {
+ InternalUnitManager unitManager = repository.getUnitManager();
+ objectAttacher = unitManager.attachObjects(context);
+ }
}
}
finally
{
- newObjects.clear();
monitor.done();
}
}
+ @Override
+ protected void writeRevisions(InternalCDORevision[] revisions, CDOBranch branch, OMMonitor monitor)
+ {
+ throw new UnsupportedOperationException();
+ }
+
protected void writeRevision(InternalCDORevision revision, boolean mapType, boolean revise, OMMonitor monitor)
{
if (TRACER.isEnabled())
@@ -708,6 +741,12 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor,
getStore().getIDHandler().adjustLastObjectID(maxID);
maxID = CDOID.NULL;
}
+
+ if (objectAttacher != null)
+ {
+ objectAttacher.finishedCommit(true);
+ objectAttacher = null;
+ }
}
finally
{
@@ -730,6 +769,12 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor,
@Override
protected final void doRollback(IStoreAccessor.CommitContext commitContext)
{
+ if (objectAttacher != null)
+ {
+ objectAttacher.finishedCommit(false);
+ objectAttacher = null;
+ }
+
getStore().getMetaDataManager().clearMetaIDMappings();
if (TRACER.isEnabled())
@@ -758,6 +803,7 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor,
DBStore store = getStore();
connection = store.getDatabase().getConnection();
connectionKeepAliveTask = new ConnectionKeepAliveTask(this);
+ objectAttacher = null;
long keepAlivePeriod = ConnectionKeepAliveTask.EXECUTION_PERIOD;
Map<String, String> storeProps = store.getProperties();
@@ -1443,6 +1489,38 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor,
manager.unlock(this, durableLockingID);
}
+ public List<CDOID> readUnitRoots()
+ {
+ UnitMappingTable unitMappingTable = getStore().getUnitMappingTable();
+ return unitMappingTable.readUnitRoots(this);
+ }
+
+ public void readUnit(IView view, CDOID rootID, CDORevisionHandler revisionHandler)
+ {
+ UnitMappingTable unitMappingTable = getStore().getUnitMappingTable();
+ unitMappingTable.readUnitRevisions(this, view, rootID, revisionHandler);
+ }
+
+ public Object initUnit(IView view, CDOID rootID, CDORevisionHandler revisionHandler, Set<CDOID> initializedIDs,
+ long timeStamp)
+ {
+ UnitMappingTable unitMappingTable = getStore().getUnitMappingTable();
+ return unitMappingTable.initUnit(this, timeStamp, view, rootID, revisionHandler, initializedIDs);
+ }
+
+ public void finishUnit(IView view, CDOID rootID, CDORevisionHandler revisionHandler, long timeStamp,
+ Object initResult, List<CDOID> ids)
+ {
+ UnitMappingTable unitMappingTable = getStore().getUnitMappingTable();
+ unitMappingTable.finishUnit((BatchedStatement)initResult, rootID, ids, timeStamp);
+ }
+
+ public void writeUnits(Map<CDOID, CDOID> unitMappings, long timeStamp)
+ {
+ UnitMappingTable unitMappingTable = getStore().getUnitMappingTable();
+ unitMappingTable.writeUnitMappings(this, unitMappings, timeStamp);
+ }
+
/**
* @author Stefan Winkler
*/
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java
index 71ad7546e0..77abb2bd05 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java
@@ -238,8 +238,11 @@ public class MetaDataManager extends Lifecycle implements IMetaDataManager
try
{
- String sql = "INSERT INTO " + CDODBSchema.PACKAGE_UNITS + " VALUES (?, ?, ?, ?)"; //$NON-NLS-1$ //$NON-NLS-2$
+ String sql = "INSERT INTO " + CDODBSchema.PACKAGE_UNITS + " (" + CDODBSchema.PACKAGE_UNITS_ID + ", " //$NON-NLS-1$ //$NON-NLS-2$
+ + CDODBSchema.PACKAGE_UNITS_ORIGINAL_TYPE + ", " + CDODBSchema.PACKAGE_UNITS_TIME_STAMP + ", "
+ + CDODBSchema.PACKAGE_UNITS_PACKAGE_DATA + ") VALUES (?, ?, ?, ?)";
DBUtil.trace(sql);
+
IDBPreparedStatement stmt = connection.prepareStatement(sql, ReuseProbability.MEDIUM);
try
@@ -311,7 +314,8 @@ public class MetaDataManager extends Lifecycle implements IMetaDataManager
String parentURI = packageInfo.getParentURI();
String unitID = packageInfo.getPackageUnit().getID();
- String sql = "INSERT INTO " + CDODBSchema.PACKAGE_INFOS + " VALUES (?, ?, ?)"; //$NON-NLS-1$ //$NON-NLS-2$
+ String sql = "INSERT INTO " + CDODBSchema.PACKAGE_INFOS + " (" + CDODBSchema.PACKAGE_INFOS_URI + ", " //$NON-NLS-1$ //$NON-NLS-2$
+ + CDODBSchema.PACKAGE_INFOS_PARENT + ", " + CDODBSchema.PACKAGE_INFOS_UNIT + ") VALUES (?, ?, ?)";
DBUtil.trace(sql);
IDBPreparedStatement stmt = connection.prepareStatement(sql, ReuseProbability.MEDIUM);
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/UUIDHandler.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/UUIDHandler.java
index 9c2b20d146..040285c0db 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/UUIDHandler.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/UUIDHandler.java
@@ -63,6 +63,7 @@ public class UUIDHandler extends Lifecycle implements IIDHandler
public int compare(CDOID id1, CDOID id2)
{
+ // UUIDs are not generated in strictly ordered form.
throw new UnsupportedOperationException();
}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java
index 9552980072..78590284f4 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java
@@ -55,6 +55,7 @@ import org.eclipse.net4j.util.StringUtil;
import org.eclipse.net4j.util.WrappedException;
import org.eclipse.net4j.util.collection.CloseableIterator;
import org.eclipse.net4j.util.lifecycle.Lifecycle;
+import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.net4j.util.om.monitor.OMMonitor;
import org.eclipse.net4j.util.om.monitor.OMMonitor.Async;
@@ -828,6 +829,21 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp
public abstract IListMapping doCreateFeatureMapMapping(EClass containingClass, EStructuralFeature feature);
+ @Override
+ protected void doDeactivate() throws Exception
+ {
+ deactivateClassMappings();
+ super.doDeactivate();
+ }
+
+ protected void deactivateClassMappings()
+ {
+ for (IClassMapping classMapping : classMappings.values())
+ {
+ LifecycleUtil.deactivate(classMapping);
+ }
+ }
+
private static Set<CDOFeatureType> doGetForceIndexes(IMappingStrategy mappingStrategy)
{
return CDOFeatureType.readCombination(mappingStrategy.getProperties().get(Props.FORCE_INDEXES));
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java
index 695e803227..b68f84dc8c 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java
@@ -13,7 +13,8 @@ package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
-import org.eclipse.emf.cdo.server.db.mapping.IListMapping2;
+import org.eclipse.emf.cdo.server.db.mapping.IClassMapping;
+import org.eclipse.emf.cdo.server.db.mapping.IListMapping3;
import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
import org.eclipse.emf.ecore.EClass;
@@ -22,7 +23,7 @@ import org.eclipse.emf.ecore.EStructuralFeature;
/**
* @author Stefan Winkler
*/
-public abstract class AbstractBasicListTableMapping implements IListMapping2, IMappingConstants
+public abstract class AbstractBasicListTableMapping implements IListMapping3, IMappingConstants
{
private IMappingStrategy mappingStrategy;
@@ -70,5 +71,10 @@ public abstract class AbstractBasicListTableMapping implements IListMapping2, IM
builder.append(toIndex - 1);
}
+ public void setClassMapping(IClassMapping classMapping)
+ {
+ // Subclasses may override.
+ }
+
public abstract void rawDeleted(IDBStoreAccessor accessor, CDOID id, CDOBranch branch, int version);
}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java
index 2efd6d6307..31581f12f7 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java
@@ -31,6 +31,7 @@ import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
import org.eclipse.emf.cdo.server.db.IIDHandler;
import org.eclipse.emf.cdo.server.db.mapping.IClassMapping;
import org.eclipse.emf.cdo.server.db.mapping.IListMapping;
+import org.eclipse.emf.cdo.server.db.mapping.IListMapping3;
import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
@@ -51,6 +52,7 @@ import org.eclipse.net4j.db.ddl.IDBIndex;
import org.eclipse.net4j.db.ddl.IDBSchema;
import org.eclipse.net4j.db.ddl.IDBTable;
import org.eclipse.net4j.spi.db.ddl.InternalDBIndex;
+import org.eclipse.net4j.util.lifecycle.IDeactivateable;
import org.eclipse.net4j.util.om.monitor.OMMonitor;
import org.eclipse.net4j.util.om.monitor.OMMonitor.Async;
import org.eclipse.net4j.util.om.trace.ContextTracer;
@@ -79,7 +81,7 @@ import java.util.Set;
* @author Eike Stepper
* @since 2.0
*/
-public abstract class AbstractHorizontalClassMapping implements IClassMapping, IMappingConstants
+public abstract class AbstractHorizontalClassMapping implements IClassMapping, IMappingConstants, IDeactivateable
{
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractHorizontalClassMapping.class);
@@ -142,7 +144,7 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I
primaryKey.addIndexField(branchField);
}
- table.addIndex(IDBIndex.Type.NON_UNIQUE, ATTRIBUTES_ID, ATTRIBUTES_REVISED);
+ table.addIndex(IDBIndex.Type.NON_UNIQUE, ATTRIBUTES_REVISED);
}
}
@@ -175,6 +177,11 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I
mapping = mappingStrategy.createListMapping(eClass, feature);
}
+ if (mapping instanceof IListMapping3)
+ {
+ ((IListMapping3)mapping).setClassMapping(this);
+ }
+
listMappings.add(mapping);
// Add field for list sizes
@@ -294,9 +301,10 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I
}
stmt.setMaxRows(1); // Optimization: only 1 row
-
resultSet = stmt.executeQuery();
- if (!resultSet.next())
+
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ if (!readValuesFromResultSet(resultSet, idHandler, revision, false))
{
if (TRACER.isEnabled())
{
@@ -306,69 +314,95 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I
return false;
}
- revision.setVersion(resultSet.getInt(ATTRIBUTES_VERSION));
+ return true;
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ finally
+ {
+ DBUtil.close(resultSet);
+ }
+ }
- long timeStamp = resultSet.getLong(ATTRIBUTES_CREATED);
+ /**
+ * Read the revision's values from the DB.
+ *
+ * @return <code>true</code> if the revision has been read successfully.<br>
+ * <code>false</code> if the revision does not exist in the DB.
+ */
+ protected final boolean readValuesFromResultSet(ResultSet resultSet, IIDHandler idHandler,
+ InternalCDORevision revision, boolean forUnit)
+ {
+ try
+ {
+ if (resultSet.next())
+ {
+ long timeStamp = resultSet.getLong(ATTRIBUTES_CREATED);
+ CDOBranchPoint branchPoint = revision.getBranch().getPoint(timeStamp);
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- CDOBranchPoint branchPoint = revision.getBranch().getPoint(timeStamp);
+ if (forUnit)
+ {
+ revision.setID(idHandler.getCDOID(resultSet, ATTRIBUTES_ID));
+ }
- revision.setBranchPoint(branchPoint);
- revision.setRevised(resultSet.getLong(ATTRIBUTES_REVISED));
- revision.setResourceID(idHandler.getCDOID(resultSet, ATTRIBUTES_RESOURCE));
- revision.setContainerID(idHandler.getCDOID(resultSet, ATTRIBUTES_CONTAINER));
- revision.setContainingFeatureID(resultSet.getInt(ATTRIBUTES_FEATURE));
+ revision.setBranchPoint(branchPoint);
+ revision.setVersion(resultSet.getInt(ATTRIBUTES_VERSION));
+ revision.setRevised(resultSet.getLong(ATTRIBUTES_REVISED));
+ revision.setResourceID(idHandler.getCDOID(resultSet, ATTRIBUTES_RESOURCE));
+ revision.setContainerID(idHandler.getCDOID(resultSet, ATTRIBUTES_CONTAINER));
+ revision.setContainingFeatureID(resultSet.getInt(ATTRIBUTES_FEATURE));
- for (ITypeMapping mapping : valueMappings)
- {
- EStructuralFeature feature = mapping.getFeature();
- if (feature.isUnsettable())
+ for (ITypeMapping mapping : valueMappings)
{
- IDBField field = unsettableFields.get(feature);
- if (!resultSet.getBoolean(field.getName()))
+ EStructuralFeature feature = mapping.getFeature();
+ if (feature.isUnsettable())
{
- // isSet==false -- setValue: null
- revision.setValue(feature, null);
- continue;
+ IDBField field = unsettableFields.get(feature);
+ if (!resultSet.getBoolean(field.getName()))
+ {
+ // isSet==false -- setValue: null
+ revision.setValue(feature, null);
+ continue;
+ }
}
- }
- mapping.readValueToRevision(resultSet, revision);
- }
+ mapping.readValueToRevision(resultSet, revision);
+ }
- if (listSizeFields != null)
- {
- for (Map.Entry<EStructuralFeature, IDBField> listSizeEntry : listSizeFields.entrySet())
+ if (listSizeFields != null)
{
- EStructuralFeature feature = listSizeEntry.getKey();
- IDBField field = listSizeEntry.getValue();
- int size = resultSet.getInt(field.getName());
+ for (Map.Entry<EStructuralFeature, IDBField> listSizeEntry : listSizeFields.entrySet())
+ {
+ EStructuralFeature feature = listSizeEntry.getKey();
+ IDBField field = listSizeEntry.getValue();
+ int size = resultSet.getInt(field.getName());
- // ensure the listSize (TODO: remove assertion)
- CDOList list = revision.getList(feature, size);
+ // ensure the listSize (TODO: remove assertion)
+ CDOList list = revision.getList(feature, size);
- for (int i = 0; i < size; i++)
- {
- list.add(InternalCDOList.UNINITIALIZED);
- }
+ for (int i = 0; i < size; i++)
+ {
+ list.add(InternalCDOList.UNINITIALIZED);
+ }
- if (list.size() != size)
- {
- Assert.isTrue(false);
+ if (list.size() != size)
+ {
+ Assert.isTrue(false);
+ }
}
}
+
+ return true;
}
- return true;
+ return false;
}
catch (SQLException ex)
{
throw new DBException(ex);
}
- finally
- {
- DBUtil.close(resultSet);
- }
}
protected final void readLists(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk)
@@ -926,6 +960,11 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I
protected abstract void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision);
+ public Exception deactivate()
+ {
+ return null;
+ }
+
protected static void appendTypeMappingNames(StringBuilder builder, Collection<ITypeMapping> typeMappings)
{
if (typeMappings != null)
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java
index 3583e2e2c5..9e1cdc6240 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java
@@ -36,11 +36,14 @@ import org.eclipse.emf.cdo.server.db.IDBStore;
import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader;
import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.mapping.IClassMapping;
import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport;
+import org.eclipse.emf.cdo.server.db.mapping.IListMappingUnitSupport;
import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
import org.eclipse.net4j.db.DBException;
import org.eclipse.net4j.db.DBType;
@@ -75,7 +78,8 @@ import java.util.List;
* @author Stefan Winkler
* @author Lothar Werzinger
*/
-public class AuditListTableMappingWithRanges extends AbstractBasicListTableMapping implements IListMappingDeltaSupport
+public class AuditListTableMappingWithRanges extends AbstractBasicListTableMapping
+ implements IListMappingDeltaSupport, IListMappingUnitSupport
{
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AuditListTableMappingWithRanges.class);
@@ -84,6 +88,11 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi
*/
private static final int FINAL_VERSION = Integer.MAX_VALUE;
+ private static final String SQL_ORDER_BY_INDEX = " ORDER BY " + LIST_IDX;
+
+ private static final boolean CHECK_UNIT_ENTRIES = Boolean
+ .getBoolean("org.eclipse.emf.cdo.server.db.checkUnitEntries");
+
/**
* The table of this mapping.
*/
@@ -97,7 +106,7 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi
// --------- SQL strings - see initSQLStrings() -----------------
private String sqlSelectChunksPrefix;
- private String sqlOrderByIndex;
+ private String sqlSelectUnitEntries;
private String sqlInsertEntry;
@@ -172,8 +181,6 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi
builder.append(">?)"); //$NON-NLS-1$
sqlSelectChunksPrefix = builder.toString();
- sqlOrderByIndex = " ORDER BY " + LIST_IDX; //$NON-NLS-1$
-
// ----------------- insert entry -----------------
builder = new StringBuilder("INSERT INTO "); //$NON-NLS-1$
builder.append(tableName);
@@ -271,6 +278,26 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi
sqlDeleteList = builder.toString();
}
+ @Override
+ public void setClassMapping(IClassMapping classMapping)
+ {
+ InternalRepository repository = (InternalRepository)getMappingStrategy().getStore().getRepository();
+ if (repository.isSupportingUnits())
+ {
+ String listTableName = getTable().getName();
+ String attributesTableName = classMapping.getDBTables().get(0).getName();
+
+ sqlSelectUnitEntries = "SELECT " + (CHECK_UNIT_ENTRIES ? ATTRIBUTES_ID + ", " : "") + "cdo_list." + LIST_VALUE + //
+ " FROM " + listTableName + " cdo_list, " + attributesTableName + ", " + UnitMappingTable.UNITS + //
+ " WHERE " + UnitMappingTable.UNITS_ELEM + "=" + ATTRIBUTES_ID + //
+ " AND " + ATTRIBUTES_ID + "=cdo_list." + LIST_REVISION_ID + //
+ " AND " + UnitMappingTable.UNITS_UNIT + "=?" + //
+ " AND cdo_list." + LIST_REVISION_VERSION_ADDED + "<=" + ATTRIBUTES_VERSION + //
+ " AND (cdo_list." + LIST_REVISION_VERSION_REMOVED + " IS NULL OR cdo_list." + LIST_REVISION_VERSION_REMOVED
+ + ">" + ATTRIBUTES_VERSION + ") ORDER BY cdo_list." + LIST_REVISION_ID + ", cdo_list." + LIST_IDX;
+ }
+ }
+
public Collection<IDBTable> getDBTables()
{
return Collections.singleton(table);
@@ -301,7 +328,7 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi
getFeature().getName(), revision.getID(), revision.getVersion());
}
- String sql = sqlSelectChunksPrefix + sqlOrderByIndex;
+ String sql = sqlSelectChunksPrefix + SQL_ORDER_BY_INDEX;
IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sql, ReuseProbability.HIGH);
@@ -365,7 +392,7 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi
builder.append(where);
}
- builder.append(sqlOrderByIndex);
+ builder.append(SQL_ORDER_BY_INDEX);
String sql = builder.toString();
IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
@@ -536,6 +563,259 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi
throw new UnsupportedOperationException("Raw deletion does not work in range-based mappings");
}
+ public ResultSet queryUnitEntries(IDBStoreAccessor accessor, IIDHandler idHandler, CDOID rootID) throws SQLException
+ {
+ IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlSelectUnitEntries,
+ ReuseProbability.MEDIUM);
+ idHandler.setCDOID(stmt, 1, rootID);
+ return stmt.executeQuery();
+ }
+
+ public void readUnitEntries(ResultSet resultSet, IIDHandler idHandler, CDOID id, MoveableList<Object> list)
+ throws SQLException
+ {
+ int size = list.size();
+ for (int i = 0; i < size; i++)
+ {
+ resultSet.next();
+
+ if (CHECK_UNIT_ENTRIES)
+ {
+ CDOID checkID = idHandler.getCDOID(resultSet, 1);
+ if (checkID != id)
+ {
+ throw new IllegalStateException("Result set does not deliver expected result");
+ }
+ }
+
+ Object value = typeMapping.readValue(resultSet);
+ list.set(i, value);
+ }
+ }
+
+ private void addEntry(IDBStoreAccessor accessor, CDOID id, int version, int index, Object value)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Adding value for feature() {0}.{1} index {2} of {3}v{4} : {5}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, version, value);
+ }
+
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlInsertEntry, ReuseProbability.HIGH);
+
+ try
+ {
+ int column = 1;
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, version);
+ stmt.setInt(column++, index);
+ typeMapping.setValue(stmt, column++, value);
+
+ DBUtil.update(stmt, true);
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ catch (IllegalStateException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ DBUtil.close(stmt);
+ }
+ }
+
+ private void removeEntry(IDBStoreAccessor accessor, CDOID id, int oldVersion, int newVersion, int index)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, newVersion);
+ }
+
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlDeleteEntry, ReuseProbability.HIGH);
+
+ try
+ {
+ // try to delete a temporary entry first
+ int column = 1;
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, index);
+ stmt.setInt(column++, newVersion);
+
+ int result = DBUtil.update(stmt, false);
+ if (result == 1)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("removeEntry deleted: {0}", index); //$NON-NLS-1$
+ }
+ }
+ else if (result > 1)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("removeEntry Too many results: {0}: {1}", index, result); //$NON-NLS-1$
+ }
+
+ throw new DBException("Too many results"); //$NON-NLS-1$
+ }
+ else
+ {
+ // no temporary entry found, so mark the entry as removed
+ DBUtil.close(stmt);
+ stmt = accessor.getDBConnection().prepareStatement(sqlRemoveEntry, ReuseProbability.HIGH);
+
+ column = 1;
+ stmt.setInt(column++, newVersion);
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, index);
+
+ DBUtil.update(stmt, true);
+ }
+ }
+ catch (SQLException e)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4} FAILED {5}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, newVersion, e.getMessage());
+ }
+
+ throw new DBException(e);
+ }
+ catch (IllegalStateException e)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4} FAILED {5}", //$NON-NLS-1$
+ getContainingClass().getName(), getFeature().getName(), index, id, newVersion, e.getMessage());
+ }
+
+ throw new DBException(e);
+ }
+ finally
+ {
+ DBUtil.close(stmt);
+ }
+ }
+
+ private Object getValue(IDBStoreAccessor accessor, CDOID id, int index)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlGetValue, ReuseProbability.HIGH);
+ Object result = null;
+
+ try
+ {
+ int column = 1;
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, index);
+
+ ResultSet resultSet = stmt.executeQuery();
+ if (!resultSet.next())
+ {
+ throw new DBException("getValue() expects exactly one result");
+ }
+
+ result = typeMapping.readValue(resultSet);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Read value (index {0}) from result set: {1}", index, result); //$NON-NLS-1$
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ DBUtil.close(stmt);
+ }
+
+ return result;
+ }
+
+ public final boolean queryXRefs(IDBStoreAccessor accessor, String mainTableName, String mainTableWhere,
+ QueryXRefsContext context, String idString)
+ {
+
+ String tableName = getTable().getName();
+ String listJoin = getMappingStrategy().getListJoin("a_t", "l_t");
+
+ StringBuilder builder = new StringBuilder();
+ builder.append("SELECT l_t."); //$NON-NLS-1$
+ builder.append(LIST_REVISION_ID);
+ builder.append(", l_t."); //$NON-NLS-1$
+ builder.append(LIST_VALUE);
+ builder.append(", l_t."); //$NON-NLS-1$
+ builder.append(LIST_IDX);
+ builder.append(" FROM "); //$NON-NLS-1$
+ builder.append(tableName);
+ builder.append(" l_t, ");//$NON-NLS-1$
+ builder.append(mainTableName);
+ builder.append(" a_t WHERE ");//$NON-NLS-1$
+ builder.append("a_t.");//$NON-NLS-1$
+ builder.append(mainTableWhere);
+ builder.append(listJoin);
+ builder.append(" AND "); //$NON-NLS-1$
+ builder.append(LIST_VALUE);
+ builder.append(" IN "); //$NON-NLS-1$
+ builder.append(idString);
+ String sql = builder.toString();
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Query XRefs (list): {0}", sql);
+ }
+
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sql, ReuseProbability.MEDIUM);
+ ResultSet resultSet = null;
+
+ try
+ {
+ resultSet = stmt.executeQuery();
+ while (resultSet.next())
+ {
+ CDOID sourceID = idHandler.getCDOID(resultSet, 1);
+ CDOID targetID = idHandler.getCDOID(resultSet, 2);
+ int idx = resultSet.getInt(3);
+
+ boolean more = context.addXRef(targetID, sourceID, (EReference)getFeature(), idx);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format(" add XRef to context: src={0}, tgt={1}, idx={2}", sourceID, targetID, idx);
+ }
+
+ if (!more)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format(" result limit reached. Ignoring further results.");
+ }
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ finally
+ {
+ DBUtil.close(resultSet);
+ DBUtil.close(stmt);
+ }
+ }
+
public void processDelta(final IDBStoreAccessor accessor, final CDOID id, final int branchId, int oldVersion,
final int newVersion, long created, CDOListFeatureDelta delta)
{
@@ -890,227 +1170,4 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi
}
}
}
-
- private void addEntry(IDBStoreAccessor accessor, CDOID id, int version, int index, Object value)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Adding value for feature() {0}.{1} index {2} of {3}v{4} : {5}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, version, value);
- }
-
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlInsertEntry, ReuseProbability.HIGH);
-
- try
- {
- int column = 1;
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, version);
- stmt.setInt(column++, index);
- typeMapping.setValue(stmt, column++, value);
-
- DBUtil.update(stmt, true);
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- catch (IllegalStateException e)
- {
- throw new DBException(e);
- }
- finally
- {
- DBUtil.close(stmt);
- }
- }
-
- private void removeEntry(IDBStoreAccessor accessor, CDOID id, int oldVersion, int newVersion, int index)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, newVersion);
- }
-
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlDeleteEntry, ReuseProbability.HIGH);
-
- try
- {
- // try to delete a temporary entry first
- int column = 1;
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, index);
- stmt.setInt(column++, newVersion);
-
- int result = DBUtil.update(stmt, false);
- if (result == 1)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("removeEntry deleted: {0}", index); //$NON-NLS-1$
- }
- }
- else if (result > 1)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("removeEntry Too many results: {0}: {1}", index, result); //$NON-NLS-1$
- }
-
- throw new DBException("Too many results"); //$NON-NLS-1$
- }
- else
- {
- // no temporary entry found, so mark the entry as removed
- DBUtil.close(stmt);
- stmt = accessor.getDBConnection().prepareStatement(sqlRemoveEntry, ReuseProbability.HIGH);
-
- column = 1;
- stmt.setInt(column++, newVersion);
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, index);
-
- DBUtil.update(stmt, true);
- }
- }
- catch (SQLException e)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4} FAILED {5}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, newVersion, e.getMessage());
- }
-
- throw new DBException(e);
- }
- catch (IllegalStateException e)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Removing value for feature() {0}.{1} index {2} of {3}v{4} FAILED {5}", //$NON-NLS-1$
- getContainingClass().getName(), getFeature().getName(), index, id, newVersion, e.getMessage());
- }
-
- throw new DBException(e);
- }
- finally
- {
- DBUtil.close(stmt);
- }
- }
-
- private Object getValue(IDBStoreAccessor accessor, CDOID id, int index)
- {
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlGetValue, ReuseProbability.HIGH);
- Object result = null;
-
- try
- {
- int column = 1;
- idHandler.setCDOID(stmt, column++, id);
- stmt.setInt(column++, index);
-
- ResultSet resultSet = stmt.executeQuery();
- if (!resultSet.next())
- {
- throw new DBException("getValue() expects exactly one result");
- }
-
- result = typeMapping.readValue(resultSet);
- if (TRACER.isEnabled())
- {
- TRACER.format("Read value (index {0}) from result set: {1}", index, result); //$NON-NLS-1$
- }
- }
- catch (SQLException e)
- {
- throw new DBException(e);
- }
- finally
- {
- DBUtil.close(stmt);
- }
-
- return result;
- }
-
- public final boolean queryXRefs(IDBStoreAccessor accessor, String mainTableName, String mainTableWhere,
- QueryXRefsContext context, String idString)
- {
-
- String tableName = getTable().getName();
- String listJoin = getMappingStrategy().getListJoin("a_t", "l_t");
-
- StringBuilder builder = new StringBuilder();
- builder.append("SELECT l_t."); //$NON-NLS-1$
- builder.append(LIST_REVISION_ID);
- builder.append(", l_t."); //$NON-NLS-1$
- builder.append(LIST_VALUE);
- builder.append(", l_t."); //$NON-NLS-1$
- builder.append(LIST_IDX);
- builder.append(" FROM "); //$NON-NLS-1$
- builder.append(tableName);
- builder.append(" l_t, ");//$NON-NLS-1$
- builder.append(mainTableName);
- builder.append(" a_t WHERE ");//$NON-NLS-1$
- builder.append("a_t.");//$NON-NLS-1$
- builder.append(mainTableWhere);
- builder.append(listJoin);
- builder.append(" AND "); //$NON-NLS-1$
- builder.append(LIST_VALUE);
- builder.append(" IN "); //$NON-NLS-1$
- builder.append(idString);
- String sql = builder.toString();
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Query XRefs (list): {0}", sql);
- }
-
- IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
- IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sql, ReuseProbability.MEDIUM);
- ResultSet resultSet = null;
-
- try
- {
- resultSet = stmt.executeQuery();
- while (resultSet.next())
- {
- CDOID sourceID = idHandler.getCDOID(resultSet, 1);
- CDOID targetID = idHandler.getCDOID(resultSet, 2);
- int idx = resultSet.getInt(3);
-
- boolean more = context.addXRef(targetID, sourceID, (EReference)getFeature(), idx);
- if (TRACER.isEnabled())
- {
- TRACER.format(" add XRef to context: src={0}, tgt={1}, idx={2}", sourceID, targetID, idx);
- }
-
- if (!more)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format(" result limit reached. Ignoring further results.");
- }
-
- return false;
- }
- }
-
- return true;
- }
- catch (SQLException ex)
- {
- throw new DBException(ex);
- }
- finally
- {
- DBUtil.close(resultSet);
- DBUtil.close(stmt);
- }
- }
}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java
index 63d4e1840c..504c82dbe0 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java
@@ -20,6 +20,7 @@ import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.revision.CDOList;
import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDOClearFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta;
@@ -35,18 +36,29 @@ import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
import org.eclipse.emf.cdo.server.db.IIDHandler;
import org.eclipse.emf.cdo.server.db.mapping.IClassMappingAuditSupport;
import org.eclipse.emf.cdo.server.db.mapping.IClassMappingDeltaSupport;
+import org.eclipse.emf.cdo.server.db.mapping.IClassMappingUnitSupport;
+import org.eclipse.emf.cdo.server.db.mapping.IListMapping;
import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport;
+import org.eclipse.emf.cdo.server.db.mapping.IListMappingUnitSupport;
import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
+import org.eclipse.emf.cdo.server.internal.db.DBStore;
import org.eclipse.emf.cdo.server.internal.db.bundle.OM;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
+import org.eclipse.emf.cdo.spi.common.revision.StubCDORevision;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
import org.eclipse.net4j.db.DBException;
import org.eclipse.net4j.db.DBUtil;
import org.eclipse.net4j.db.IDBPreparedStatement;
import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability;
+import org.eclipse.net4j.db.IDBResultSet;
import org.eclipse.net4j.db.ddl.IDBField;
import org.eclipse.net4j.util.ImplementationError;
+import org.eclipse.net4j.util.WrappedException;
+import org.eclipse.net4j.util.collection.MoveableList;
+import org.eclipse.net4j.util.concurrent.ConcurrencyUtil;
+import org.eclipse.net4j.util.concurrent.TimeoutRuntimeException;
import org.eclipse.net4j.util.om.monitor.OMMonitor;
import org.eclipse.net4j.util.om.monitor.OMMonitor.Async;
import org.eclipse.net4j.util.om.trace.ContextTracer;
@@ -54,28 +66,38 @@ import org.eclipse.net4j.util.om.trace.ContextTracer;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EStructuralFeature;
+import java.sql.ResultSet;
import java.sql.SQLException;
+import java.util.List;
import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
/**
* @author Eike Stepper
* @since 2.0
*/
public class HorizontalAuditClassMapping extends AbstractHorizontalClassMapping
- implements IClassMappingAuditSupport, IClassMappingDeltaSupport
+ implements IClassMappingAuditSupport, IClassMappingDeltaSupport, IClassMappingUnitSupport
{
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, HorizontalAuditClassMapping.class);
private String sqlInsertAttributes;
- private String sqlSelectCurrentAttributes;
-
- private String sqlSelectAllObjectIDs;
+ private String sqlSelectAttributesCurrent;
private String sqlSelectAttributesByTime;
private String sqlSelectAttributesByVersion;
+ private String sqlSelectUnitCurrent;
+
+ private String sqlSelectUnitByTime;
+
+ private String sqlSelectAllObjectIDs;
+
private String sqlReviseAttributes;
private String sqlRawDeleteAttributes;
@@ -98,47 +120,25 @@ public class HorizontalAuditClassMapping extends AbstractHorizontalClassMapping
private void initSQLStrings()
{
// ----------- Select Revision ---------------------------
- StringBuilder builder = new StringBuilder();
- builder.append("SELECT "); //$NON-NLS-1$
- builder.append(ATTRIBUTES_VERSION);
- builder.append(", "); //$NON-NLS-1$
- builder.append(ATTRIBUTES_CREATED);
- builder.append(", "); //$NON-NLS-1$
- builder.append(ATTRIBUTES_REVISED);
- builder.append(", "); //$NON-NLS-1$
- builder.append(ATTRIBUTES_RESOURCE);
- builder.append(", "); //$NON-NLS-1$
- builder.append(ATTRIBUTES_CONTAINER);
- builder.append(", "); //$NON-NLS-1$
- builder.append(ATTRIBUTES_FEATURE);
- appendTypeMappingNames(builder, getValueMappings());
- appendFieldNames(builder, getUnsettableFields());
- appendFieldNames(builder, getListSizeFields());
- builder.append(" FROM "); //$NON-NLS-1$
- builder.append(getTable());
- builder.append(" WHERE "); //$NON-NLS-1$
- builder.append(ATTRIBUTES_ID);
- builder.append("=? AND ("); //$NON-NLS-1$
- String sqlSelectAttributesPrefix = builder.toString();
- builder.append(ATTRIBUTES_REVISED);
- builder.append("=0)"); //$NON-NLS-1$
- sqlSelectCurrentAttributes = builder.toString();
+ String[] strings = buildSQLSelects(false);
+ String sqlSelectAttributesPrefix = strings[0];
+ sqlSelectAttributesCurrent = strings[1];
+ sqlSelectAttributesByTime = strings[2];
- builder = new StringBuilder(sqlSelectAttributesPrefix);
- builder.append(ATTRIBUTES_CREATED);
- builder.append("<=? AND ("); //$NON-NLS-1$
- builder.append(ATTRIBUTES_REVISED);
- builder.append("=0 OR "); //$NON-NLS-1$
- builder.append(ATTRIBUTES_REVISED);
- builder.append(">=?))"); //$NON-NLS-1$
- sqlSelectAttributesByTime = builder.toString();
-
- builder = new StringBuilder(sqlSelectAttributesPrefix);
+ StringBuilder builder = new StringBuilder(sqlSelectAttributesPrefix);
builder.append("ABS(");
builder.append(ATTRIBUTES_VERSION);
- builder.append(")=?)"); //$NON-NLS-1$
+ builder.append(")=?"); //$NON-NLS-1$
sqlSelectAttributesByVersion = builder.toString();
+ InternalRepository repository = (InternalRepository)getMappingStrategy().getStore().getRepository();
+ if (repository.isSupportingUnits())
+ {
+ strings = buildSQLSelects(true);
+ sqlSelectUnitCurrent = strings[1];
+ sqlSelectUnitByTime = strings[2];
+ }
+
// ----------- Insert Attributes -------------------------
builder = new StringBuilder();
builder.append("INSERT INTO "); //$NON-NLS-1$
@@ -200,6 +200,92 @@ public class HorizontalAuditClassMapping extends AbstractHorizontalClassMapping
sqlRawDeleteAttributes = builder.toString();
}
+ private String[] buildSQLSelects(boolean forUnits)
+ {
+ String[] strings = new String[3];
+
+ StringBuilder builder = new StringBuilder();
+ builder.append("SELECT "); //$NON-NLS-1$
+ if (forUnits)
+ {
+ builder.append(ATTRIBUTES_ID);
+ builder.append(", "); //$NON-NLS-1$
+ }
+
+ builder.append(ATTRIBUTES_VERSION);
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(ATTRIBUTES_CREATED);
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(ATTRIBUTES_REVISED);
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(ATTRIBUTES_RESOURCE);
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(ATTRIBUTES_CONTAINER);
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(ATTRIBUTES_FEATURE);
+ appendTypeMappingNames(builder, getValueMappings());
+ appendFieldNames(builder, getUnsettableFields());
+ appendFieldNames(builder, getListSizeFields());
+ builder.append(" FROM "); //$NON-NLS-1$
+ builder.append(getTable());
+
+ if (forUnits)
+ {
+ builder.append(", "); //$NON-NLS-1$
+ builder.append(UnitMappingTable.UNITS);
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(ATTRIBUTES_ID);
+ builder.append("="); //$NON-NLS-1$
+ builder.append(UnitMappingTable.UNITS);
+ builder.append("."); //$NON-NLS-1$
+ builder.append(UnitMappingTable.UNITS_ELEM);
+ builder.append(" AND "); //$NON-NLS-1$
+ builder.append(UnitMappingTable.UNITS);
+ builder.append("."); //$NON-NLS-1$
+ builder.append(UnitMappingTable.UNITS_UNIT);
+ builder.append("=?"); //$NON-NLS-1$
+ builder.append(" AND "); //$NON-NLS-1$
+ }
+ else
+ {
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(ATTRIBUTES_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ }
+
+ strings[0] = builder.toString();
+
+ builder.append(ATTRIBUTES_REVISED);
+ builder.append("=0"); //$NON-NLS-1$
+
+ if (forUnits)
+ {
+ builder.append(" ORDER BY "); //$NON-NLS-1$
+ builder.append(ATTRIBUTES_ID);
+ }
+
+ strings[1] = builder.toString();
+
+ builder = new StringBuilder(strings[0]);
+ builder.append("("); //$NON-NLS-1$
+ builder.append(ATTRIBUTES_CREATED);
+ builder.append("<=? AND ("); //$NON-NLS-1$
+ builder.append(ATTRIBUTES_REVISED);
+ builder.append("=0 OR "); //$NON-NLS-1$
+ builder.append(ATTRIBUTES_REVISED);
+ builder.append(">=?))"); //$NON-NLS-1$
+
+ if (forUnits)
+ {
+ builder.append(" ORDER BY "); //$NON-NLS-1$
+ builder.append(ATTRIBUTES_ID);
+ }
+
+ strings[2] = builder.toString();
+
+ return strings;
+ }
+
public boolean readRevision(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk)
{
IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
@@ -217,7 +303,7 @@ public class HorizontalAuditClassMapping extends AbstractHorizontalClassMapping
}
else
{
- stmt = accessor.getDBConnection().prepareStatement(sqlSelectCurrentAttributes, ReuseProbability.HIGH);
+ stmt = accessor.getDBConnection().prepareStatement(sqlSelectAttributesCurrent, ReuseProbability.HIGH);
idHandler.setCDOID(stmt, 1, revision.getID());
}
@@ -593,6 +679,210 @@ public class HorizontalAuditClassMapping extends AbstractHorizontalClassMapping
return builder.toString();
}
+ public void readUnitRevisions(IDBStoreAccessor accessor, CDOBranchPoint branchPoint, CDOID rootID,
+ CDORevisionHandler revisionHandler) throws SQLException
+ {
+ DBStore store = (DBStore)getMappingStrategy().getStore();
+ InternalRepository repository = store.getRepository();
+ CDOBranchPoint head = repository.getBranchManager().getMainBranch().getHead();
+ EClass eClass = getEClass();
+
+ IIDHandler idHandler = store.getIDHandler();
+ IDBPreparedStatement stmt = null;
+ int oldFetchSize = -1;
+
+ try
+ {
+ long timeStamp = branchPoint.getTimeStamp();
+ if (timeStamp != CDOBranchPoint.UNSPECIFIED_DATE)
+ {
+ stmt = accessor.getDBConnection().prepareStatement(sqlSelectUnitByTime, ReuseProbability.MEDIUM);
+ idHandler.setCDOID(stmt, 1, rootID);
+ stmt.setLong(2, timeStamp);
+ stmt.setLong(3, timeStamp);
+ }
+ else
+ {
+ stmt = accessor.getDBConnection().prepareStatement(sqlSelectUnitCurrent, ReuseProbability.HIGH);
+ idHandler.setCDOID(stmt, 1, rootID);
+ }
+
+ AsnychronousListFiller listFiller = new AsnychronousListFiller(accessor, rootID, revisionHandler);
+ ConcurrencyUtil.execute(repository, listFiller);
+
+ oldFetchSize = stmt.getFetchSize();
+ stmt.setFetchSize(100000);
+ IDBResultSet resultSet = stmt.executeQuery();
+
+ for (;;)
+ {
+ InternalCDORevision revision = store.createRevision(eClass, null);
+ revision.setBranchPoint(head);
+
+ if (!readValuesFromResultSet(resultSet, idHandler, revision, true))
+ {
+ break;
+ }
+
+ listFiller.schedule(revision);
+ }
+
+ listFiller.await();
+ }
+ finally
+ {
+ if (oldFetchSize != -1)
+ {
+ stmt.setFetchSize(oldFetchSize);
+ }
+
+ DBUtil.close(stmt);
+ }
+ }
+
+ private class AsnychronousListFiller implements Runnable
+ {
+ private final BlockingQueue<InternalCDORevision> queue = new LinkedBlockingQueue<InternalCDORevision>();
+
+ private final CountDownLatch latch = new CountDownLatch(1);
+
+ private final IDBStoreAccessor accessor;
+
+ private final CDOID rootID;
+
+ private final DBStore store;
+
+ private final IIDHandler idHandler;
+
+ private final IListMappingUnitSupport[] listMappings;
+
+ private final ResultSet[] resultSets;
+
+ private final CDORevisionHandler revisionHandler;
+
+ private Throwable exception;
+
+ public AsnychronousListFiller(IDBStoreAccessor accessor, CDOID rootID, CDORevisionHandler revisionHandler)
+ {
+ this.accessor = accessor;
+ this.rootID = rootID;
+ this.revisionHandler = revisionHandler;
+
+ store = (DBStore)accessor.getStore();
+ idHandler = store.getIDHandler();
+
+ List<IListMapping> tmp = getListMappings();
+ int size = tmp.size();
+
+ listMappings = new IListMappingUnitSupport[size];
+ resultSets = new ResultSet[size];
+
+ int i = 0;
+ for (IListMapping listMapping : tmp)
+ {
+ listMappings[i++] = (IListMappingUnitSupport)listMapping;
+ }
+ }
+
+ public void schedule(InternalCDORevision revision)
+ {
+ queue.offer(revision);
+ }
+
+ public void await() throws SQLException
+ {
+ // Schedule an end marker revision.
+ schedule(new StubCDORevision(getEClass()));
+
+ try
+ {
+ latch.await();
+ }
+ catch (InterruptedException ex)
+ {
+ throw new TimeoutRuntimeException();
+ }
+
+ if (exception instanceof RuntimeException)
+ {
+ throw (RuntimeException)exception;
+ }
+
+ if (exception instanceof Error)
+ {
+ throw (Error)exception;
+ }
+
+ if (exception instanceof SQLException)
+ {
+ throw (SQLException)exception;
+ }
+
+ if (exception instanceof Exception)
+ {
+ throw WrappedException.wrap((Exception)exception);
+ }
+ }
+
+ public void run()
+ {
+ try
+ {
+ while (store.isActive())
+ {
+ InternalCDORevision revision = queue.poll(1, TimeUnit.SECONDS);
+ if (revision == null)
+ {
+ continue;
+ }
+
+ if (revision instanceof StubCDORevision)
+ {
+ return;
+ }
+
+ readUnitEntries(revision);
+ }
+ }
+ catch (Throwable ex)
+ {
+ exception = ex;
+ }
+ finally
+ {
+ latch.countDown();
+ }
+ }
+
+ private void readUnitEntries(InternalCDORevision revision) throws SQLException
+ {
+ CDOID id = revision.getID();
+
+ for (int i = 0; i < listMappings.length; i++)
+ {
+ IListMappingUnitSupport listMapping = listMappings[i];
+ EStructuralFeature feature = listMapping.getFeature();
+
+ MoveableList<Object> list = revision.getList(feature);
+ int size = list.size();
+ if (size != 0)
+ {
+ if (resultSets[i] == null)
+ {
+ resultSets[i] = listMapping.queryUnitEntries(accessor, idHandler, rootID);
+ }
+
+ listMapping.readUnitEntries(resultSets[i], idHandler, id, list);
+ }
+ }
+
+ synchronized (revisionHandler)
+ {
+ revisionHandler.handleRevision(revision);
+ }
+ }
+ }
+
/**
* @author Stefan Winkler
*/
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java
index 3a3b6795a2..85c1855bf7 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java
@@ -368,6 +368,8 @@ public class HorizontalNonAuditClassMapping extends AbstractHorizontalClassMappi
{
if (hasLists)
{
+ // Reading all list rows of an object is not atomic.
+ // After all row reads are done, check the revision version again (see below).
stmtVersion = accessor.getDBConnection().prepareStatement(sqlSelectCurrentVersion, ReuseProbability.HIGH);
stmtVersion.setMaxRows(1); // Optimization: only 1 row
idHandler.setCDOID(stmtVersion, 1, id);
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java
index cade3cb771..5787470f50 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java
@@ -21,6 +21,7 @@ import org.eclipse.emf.cdo.server.db.IDBStore;
import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
import org.eclipse.emf.cdo.server.db.IIDHandler;
import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
import org.eclipse.net4j.db.DBException;
import org.eclipse.net4j.db.DBType;
@@ -213,7 +214,7 @@ public class ObjectTypeTable extends AbstractObjectTypeMapper implements IMappin
{
super.doActivate();
- IDBStore store = getMappingStrategy().getStore();
+ final IDBStore store = getMappingStrategy().getStore();
final DBType idType = store.getIDHandler().getDBType();
final int idLength = store.getIDColumnLength();
@@ -230,6 +231,12 @@ public class ObjectTypeTable extends AbstractObjectTypeMapper implements IMappin
table.addField(ATTRIBUTES_CLASS, idType, idLength);
table.addField(ATTRIBUTES_CREATED, DBType.BIGINT);
table.addIndex(IDBIndex.Type.PRIMARY_KEY, ATTRIBUTES_ID);
+
+ InternalRepository repository = (InternalRepository)store.getRepository();
+ if (repository.isSupportingUnits())
+ {
+ table.addIndex(IDBIndex.Type.NON_UNIQUE, ATTRIBUTES_CLASS);
+ }
}
});
}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/UnitMappingTable.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/UnitMappingTable.java
new file mode 100644
index 0000000000..4bdacb754f
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/UnitMappingTable.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2010-2014 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ * Stefan Winkler - bug 259402
+ * Stefan Winkler - redesign (prepared statements)
+ * Stefan Winkler - bug 276926
+ */
+package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
+import org.eclipse.emf.cdo.server.IView;
+import org.eclipse.emf.cdo.server.db.IDBStore;
+import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.IMetaDataManager;
+import org.eclipse.emf.cdo.server.db.mapping.IClassMappingUnitSupport;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
+
+import org.eclipse.net4j.db.BatchedStatement;
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.IDBConnection;
+import org.eclipse.net4j.db.IDBDatabase;
+import org.eclipse.net4j.db.IDBDatabase.RunnableWithSchema;
+import org.eclipse.net4j.db.IDBPreparedStatement;
+import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability;
+import org.eclipse.net4j.db.ddl.IDBIndex;
+import org.eclipse.net4j.db.ddl.IDBSchema;
+import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.util.lifecycle.Lifecycle;
+
+import org.eclipse.emf.ecore.EClass;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * @author Eike Stepper
+ * @since 4.0
+ */
+public class UnitMappingTable extends Lifecycle implements IMappingConstants
+{
+ public static final String UNITS = "CDO_UNITS"; //$NON-NLS-1$
+
+ public static final String UNITS_ELEM = "CDO_ELEM"; //$NON-NLS-1$
+
+ public static final String UNITS_UNIT = "CDO_UNIT"; //$NON-NLS-1$
+
+ // public static final String UNITS_CREATED = "CDO_CREATED"; //$NON-NLS-1$
+
+ private static final String SQL_SELECT_ROOTS = "SELECT DISTINCT " + UNITS_UNIT + " FROM " + UNITS;
+
+ private static final String SQL_INSERT_MAPPINGS = "INSERT INTO " + UNITS + " (" + UNITS_ELEM + ", " + UNITS_UNIT
+ + ") VALUES (?, ?)";
+
+ private static final String SQL_SELECT_CLASSES = "SELECT DISTINCT " + ATTRIBUTES_CLASS + " FROM " + UNITS + ", "
+ + CDODBSchema.CDO_OBJECTS + " WHERE " + UNITS_ELEM + "=" + ATTRIBUTES_ID + " AND " + UNITS_UNIT + "=?";
+
+ private static final int WRITE_UNIT_MAPPING_BATCH_SIZE = 100000;
+
+ private final IMappingStrategy mappingStrategy;
+
+ private IDBTable table;
+
+ public UnitMappingTable(IMappingStrategy mappingStrategy)
+ {
+ this.mappingStrategy = mappingStrategy;
+ }
+
+ public List<CDOID> readUnitRoots(IDBStoreAccessor accessor)
+ {
+ List<CDOID> rootIDs = new ArrayList<CDOID>();
+ IIDHandler idHandler = mappingStrategy.getStore().getIDHandler();
+ Statement stmt = null;
+
+ try
+ {
+ stmt = accessor.getDBConnection().createStatement();
+
+ if (DBUtil.isTracerEnabled())
+ {
+ DBUtil.trace(stmt.toString());
+ }
+
+ ResultSet resultSet = stmt.executeQuery(SQL_SELECT_ROOTS);
+ while (resultSet.next())
+ {
+ CDOID rootID = idHandler.getCDOID(resultSet, 1);
+ rootIDs.add(rootID);
+ }
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ finally
+ {
+ DBUtil.close(stmt);
+ }
+
+ return rootIDs;
+ }
+
+ public void readUnitRevisions(IDBStoreAccessor accessor, IView view, CDOID rootID, CDORevisionHandler revisionHandler)
+ {
+ IDBStore store = mappingStrategy.getStore();
+ IIDHandler idHandler = store.getIDHandler();
+ IMetaDataManager metaDataManager = store.getMetaDataManager();
+
+ IDBConnection connection = accessor.getDBConnection();
+ IDBPreparedStatement stmt = connection.prepareStatement(SQL_SELECT_CLASSES, ReuseProbability.HIGH);
+ int oldFetchSize = -1;
+
+ try
+ {
+ idHandler.setCDOID(stmt, 1, rootID);
+
+ oldFetchSize = stmt.getFetchSize();
+ stmt.setFetchSize(100000);
+ ResultSet resultSet = stmt.executeQuery();
+
+ while (resultSet.next())
+ {
+ CDOID classID = idHandler.getCDOID(resultSet, 1);
+ EClass eClass = (EClass)metaDataManager.getMetaInstance(classID);
+
+ IClassMappingUnitSupport classMapping = (IClassMappingUnitSupport)mappingStrategy.getClassMapping(eClass);
+ classMapping.readUnitRevisions(accessor, view, rootID, revisionHandler);
+ }
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ finally
+ {
+ if (oldFetchSize != -1)
+ {
+ try
+ {
+ stmt.setFetchSize(oldFetchSize);
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ }
+
+ DBUtil.close(stmt);
+ }
+ }
+
+ public BatchedStatement initUnit(IDBStoreAccessor accessor, long timeStamp, IView view, CDOID rootID,
+ CDORevisionHandler revisionHandler, Set<CDOID> initializedIDs)
+ {
+ IIDHandler idHandler = mappingStrategy.getStore().getIDHandler();
+ IDBConnection connection = accessor.getDBConnection();
+ BatchedStatement stmt = DBUtil.batched(connection.prepareStatement(SQL_INSERT_MAPPINGS, ReuseProbability.HIGH),
+ WRITE_UNIT_MAPPING_BATCH_SIZE);
+
+ try
+ {
+ CDORevision revision = view.getRevision(rootID);
+
+ initUnit(stmt, view, rootID, revisionHandler, initializedIDs, timeStamp, idHandler, revision);
+ return stmt;
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ finally
+ {
+ // Don't close the statement; that's done later in finishUnit().
+ }
+ }
+
+ private void initUnit(BatchedStatement stmt, IView view, CDOID rootID, CDORevisionHandler revisionHandler,
+ Set<CDOID> initializedIDs, long timeStamp, IIDHandler idHandler, CDORevision revision) throws SQLException
+ {
+ revisionHandler.handleRevision(revision);
+
+ CDOID id = revision.getID();
+ initializedIDs.add(id);
+
+ writeUnitMapping(stmt, rootID, timeStamp, idHandler, id);
+
+ List<CDORevision> children = CDORevisionUtil.getChildRevisions(revision, view, true);
+ for (CDORevision child : children)
+ {
+ initUnit(stmt, view, rootID, revisionHandler, initializedIDs, timeStamp, idHandler, child);
+ }
+ }
+
+ public void finishUnit(BatchedStatement stmt, CDOID rootID, List<CDOID> ids, long timeStamp)
+ {
+ IDBStore store = mappingStrategy.getStore();
+ IIDHandler idHandler = store.getIDHandler();
+ Connection connection = null;
+
+ try
+ {
+ connection = stmt.getConnection();
+
+ for (CDOID id : ids)
+ {
+ writeUnitMapping(stmt, rootID, timeStamp, idHandler, id);
+ }
+ }
+ catch (SQLException ex)
+ {
+ DBUtil.rollbackSilently(connection);
+ throw new DBException(ex);
+ }
+ finally
+ {
+ DBUtil.close(stmt);
+ }
+
+ try
+ {
+ connection.commit();
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ }
+
+ public void writeUnitMappings(IDBStoreAccessor accessor, Map<CDOID, CDOID> unitMappings, long timeStamp)
+ {
+ IIDHandler idHandler = mappingStrategy.getStore().getIDHandler();
+ IDBConnection connection = accessor.getDBConnection();
+ BatchedStatement stmt = DBUtil.batched(connection.prepareStatement(SQL_INSERT_MAPPINGS, ReuseProbability.HIGH),
+ WRITE_UNIT_MAPPING_BATCH_SIZE);
+
+ try
+ {
+ for (Entry<CDOID, CDOID> entry : unitMappings.entrySet())
+ {
+ CDOID id = entry.getKey();
+ CDOID rootID = entry.getValue();
+ writeUnitMapping(stmt, rootID, timeStamp, idHandler, id);
+ }
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ finally
+ {
+ DBUtil.close(stmt);
+ }
+ }
+
+ private void writeUnitMapping(BatchedStatement stmt, CDOID rootID, long timeStamp, IIDHandler idHandler, CDOID id)
+ throws SQLException
+ {
+ idHandler.setCDOID(stmt, 1, id);
+ idHandler.setCDOID(stmt, 2, rootID);
+ // stmt.setLong(3, timeStamp);
+ stmt.executeUpdate();
+ }
+
+ @Override
+ protected void doActivate() throws Exception
+ {
+ super.doActivate();
+
+ IDBStore store = mappingStrategy.getStore();
+ final DBType idType = store.getIDHandler().getDBType();
+ final int idLength = store.getIDColumnLength();
+
+ IDBDatabase database = store.getDatabase();
+ table = database.getSchema().getTable(UNITS);
+ if (table == null)
+ {
+ database.updateSchema(new RunnableWithSchema()
+ {
+ public void run(IDBSchema schema)
+ {
+ table = schema.addTable(UNITS);
+ table.addField(UNITS_ELEM, idType, idLength, true);
+ table.addField(UNITS_UNIT, idType, idLength);
+ // table.addField(UNITS_CREATED, DBType.BIGINT);
+ table.addIndex(IDBIndex.Type.PRIMARY_KEY, UNITS_ELEM);
+ table.addIndex(IDBIndex.Type.NON_UNIQUE, UNITS_UNIT);
+ }
+ });
+ }
+ }
+
+ @Override
+ protected void doDeactivate() throws Exception
+ {
+ table = null;
+ super.doDeactivate();
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateRawCommitContext.java b/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateRawCommitContext.java
index abf8fb61a0..c6ce59833c 100644
--- a/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateRawCommitContext.java
+++ b/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateRawCommitContext.java
@@ -20,6 +20,7 @@ import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.server.IStoreAccessor;
import org.eclipse.emf.cdo.server.IView;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
@@ -47,7 +48,6 @@ import java.util.Set;
*/
public class HibernateRawCommitContext implements InternalCommitContext
{
-
private Map<CDOID, CDOID> idMappings = CDOIDUtil.createMap();
private List<InternalCDORevision> dirtyObjects = new ArrayList<InternalCDORevision>();
@@ -245,6 +245,11 @@ public class HibernateRawCommitContext implements InternalCommitContext
this.newObjects = newObjects;
}
+ public IStoreAccessor getAccessor()
+ {
+ return null;
+ }
+
public void preWrite()
{
}
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java
index 158ec41677..8b87235fcd 100644
--- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerProtocol.java
@@ -391,6 +391,9 @@ public class CDOServerProtocol extends SignalProtocol<InternalSession> implement
case SIGNAL_RESET_TRANSACTION:
return new ResetTransactionIndication(this);
+ case SIGNAL_UNIT:
+ return new UnitIndication(this);
+
default:
return super.createSignalReactor(signalID);
}
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/UnitIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/UnitIndication.java
new file mode 100644
index 0000000000..7277f935fa
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/UnitIndication.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.internal.net4j.protocol;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.server.IUnit;
+import org.eclipse.emf.cdo.server.IUnitManager;
+import org.eclipse.emf.cdo.spi.server.InternalView;
+
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+import org.eclipse.net4j.util.om.monitor.OMMonitor.Async;
+
+import java.io.IOException;
+
+/**
+ * @author Eike Stepper
+ */
+public class UnitIndication extends CDOServerReadIndicationWithMonitoring
+{
+ private int viewID;
+
+ private CDOID rootID;
+
+ private byte opcode;
+
+ public UnitIndication(CDOServerProtocol protocol)
+ {
+ super(protocol, CDOProtocolConstants.SIGNAL_UNIT);
+ }
+
+ @Override
+ protected void indicating(CDODataInput in, OMMonitor monitor) throws Exception
+ {
+ viewID = in.readInt();
+ rootID = in.readCDOID();
+ opcode = in.readByte();
+ }
+
+ @Override
+ protected void responding(final CDODataOutput out, OMMonitor monitor) throws Exception
+ {
+ final InternalView view = getView(viewID);
+ IUnitManager unitManager = getRepository().getUnitManager();
+
+ if (opcode == CDOProtocolConstants.UNIT_CHECK)
+ {
+ out.writeBoolean(unitManager.isUnit(rootID));
+ return;
+ }
+
+ if (opcode == CDOProtocolConstants.UNIT_CLOSE)
+ {
+ IUnit unit = unitManager.getUnit(rootID);
+ if (unit != null)
+ {
+ unit.close(view);
+ out.writeBoolean(true);
+ return;
+ }
+
+ out.writeBoolean(false);
+ return;
+ }
+
+ final IOException[] ioException = { null };
+ final RuntimeException[] runtimeException = { null };
+
+ monitor.begin();
+ Async async = monitor.forkAsync();
+
+ try
+ {
+ boolean success = view.openUnit(rootID, opcode == CDOProtocolConstants.UNIT_CREATE, new CDORevisionHandler()
+ {
+ public boolean handleRevision(CDORevision revision)
+ {
+ try
+ {
+ view.unsubscribe(revision.getID());
+ out.writeCDORevision(revision, CDORevision.UNCHUNKED); // Exposes revision to client side
+ return true;
+ }
+ catch (IOException ex)
+ {
+ ioException[0] = ex;
+ }
+ catch (RuntimeException ex)
+ {
+ runtimeException[0] = ex;
+ }
+
+ return false;
+ }
+ });
+
+ if (ioException[0] != null)
+ {
+ throw ioException[0];
+ }
+
+ if (runtimeException[0] != null)
+ {
+ throw runtimeException[0];
+ }
+
+ out.writeCDORevision(null, CDORevision.UNCHUNKED); // No more revisions
+ out.writeBoolean(success);
+ }
+ finally
+ {
+ async.stop();
+ monitor.done();
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.product/CDOServer.launch b/plugins/org.eclipse.emf.cdo.server.product/CDOServer.launch
index 27049b215f..9ef9177045 100644
--- a/plugins/org.eclipse.emf.cdo.server.product/CDOServer.launch
+++ b/plugins/org.eclipse.emf.cdo.server.product/CDOServer.launch
@@ -26,7 +26,7 @@
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl}&#13;&#10;-debug&#13;&#10;-console"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms40m&#13;&#10;-Xmx1g&#13;&#10;-Ddebug=true&#13;&#10;-Dorg.eclipse.net4j.tcp.ssl.passphrase=ab987c&#10;&#13;&#10;-Dorg.eclipse.net4j.tcp.ssl.trust=file:///${workspace_loc:org.eclipse.emf.cdo.examples}/sslKey/testTrust&#13;&#10;&#10;-Dorg.eclipse.net4j.tcp.ssl.key=file:///${workspace_loc:org.eclipse.emf.cdo.examples}/sslKey/testKeys&#10;&#13;&#10;-Dorg.eclipse.emf.cdo.server.browser.port=7777&#13;&#10;-Dorg.osgi.service.http.port=8080&#13;&#10;-Dosgi.checkConfiguration=false"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1G&#13;&#10;-Xmx1G&#13;&#10;-Ddebug=true&#13;&#10;-Dorg.eclipse.net4j.tcp.ssl.passphrase=ab987c&#10;&#13;&#10;-Dorg.eclipse.net4j.tcp.ssl.trust=file:///${workspace_loc:org.eclipse.emf.cdo.examples}/sslKey/testTrust&#13;&#10;&#10;-Dorg.eclipse.net4j.tcp.ssl.key=file:///${workspace_loc:org.eclipse.emf.cdo.examples}/sslKey/testKeys&#10;&#13;&#10;-Dorg.eclipse.emf.cdo.server.browser.port=7777&#13;&#10;-Dorg.osgi.service.http.port=8080&#13;&#10;-Dosgi.checkConfiguration=false"/>
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc:org.eclipse.emf.cdo.server.product}"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.platform.ide"/>
diff --git a/plugins/org.eclipse.emf.cdo.server.product/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.server.product/META-INF/MANIFEST.MF
index a0623e833d..dd63b31d06 100644
--- a/plugins/org.eclipse.emf.cdo.server.product/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.cdo.server.product/META-INF/MANIFEST.MF
@@ -1,7 +1,7 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.eclipse.emf.cdo.server.product;singleton:=true
-Bundle-Version: 4.1.300.qualifier
+Bundle-Version: 4.1.400.qualifier
Bundle-Name: %pluginName
Bundle-Vendor: %providerName
Bundle-Localization: plugin
diff --git a/plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml b/plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml
index 3bf0040baf..a5e09ecb46 100644
--- a/plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml
+++ b/plugins/org.eclipse.emf.cdo.server.product/config/cdo-server.xml
@@ -17,6 +17,7 @@
<property name="overrideUUID" value=""/>
<property name="supportingAudits" value="true"/>
<property name="supportingBranches" value="true"/>
+ <property name="supportingUnits" value="false"/>
<property name="ensureReferentialIntegrity" value="false"/>
<property name="allowInterruptRunningQueries" value="true"/>
<property name="idGenerationLocation" value="STORE"/> <!-- Possible values: STORE | CLIENT -->
@@ -52,6 +53,7 @@
<mappingStrategy type="horizontal"> <!-- callout -->
<property name="qualifiedNames" value="true"/>
+ <property name="withRanges" value="false"/>
<!--
Per default, the objectTypeCache is in-memory and contains
@@ -59,17 +61,15 @@
uncomment the following line and set the desired size.
The cache can be disabled by setting a size of 0.
-->
-
<!-- Optional:
<property name="objectTypeCacheSize" value="100000"/>
-->
-
</mappingStrategy>
<dbAdapter name="h2"/>
<dataSource class="org.h2.jdbcx.JdbcDataSource"
- URL="jdbc:h2:database/repo1"/>
-
+ URL="jdbc:h2:/develop/cdo-master/h2/big"/>
+
<!-- Example:
<dbAdapter name="derby-embedded"/>
<dataSource class="org.apache.derby.jdbc.EmbeddedDataSource"
@@ -87,8 +87,8 @@
<!-- Example:
<dbAdapter name="mysql"/>
<dataSource class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
- url="jdbc:mysql://localhost/repo1"
- user="sa"/>
+ url="jdbc:mysql://localhost/big"
+ user="test" password="0000"/>
-->
<!-- Example:
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
index 25ede606b0..bb485055dd 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
@@ -92,6 +92,7 @@ import org.eclipse.emf.cdo.spi.server.InternalSession;
import org.eclipse.emf.cdo.spi.server.InternalSessionManager;
import org.eclipse.emf.cdo.spi.server.InternalStore;
import org.eclipse.emf.cdo.spi.server.InternalTransaction;
+import org.eclipse.emf.cdo.spi.server.InternalUnitManager;
import org.eclipse.emf.cdo.spi.server.InternalView;
import org.eclipse.emf.internal.cdo.object.CDOFactoryImpl;
@@ -147,7 +148,7 @@ import java.util.concurrent.Semaphore;
* @author Eike Stepper
* @since 2.0
*/
-public class Repository extends Container<Object>implements InternalRepository, IExecutorServiceProvider
+public class Repository extends Container<Object> implements InternalRepository, IExecutorServiceProvider
{
private static final int UNCHUNKED = CDORevision.UNCHUNKED;
@@ -169,6 +170,8 @@ public class Repository extends Container<Object>implements InternalRepository,
private boolean supportingBranches;
+ private boolean supportingUnits;
+
private boolean serializingCommits;
private boolean ensuringReferentialIntegrity;
@@ -180,7 +183,7 @@ public class Repository extends Container<Object>implements InternalRepository,
/**
* Must not be thread-bound to support XA commits.
*/
- private Semaphore packageRegistryCommitLock = new Semaphore(1);
+ private final Semaphore packageRegistryCommitLock = new Semaphore(1);
private InternalCDOPackageRegistry packageRegistry;
@@ -198,31 +201,33 @@ public class Repository extends Container<Object>implements InternalRepository,
private InternalLockManager lockingManager;
+ private InternalUnitManager unitManager;
+
private IQueryHandlerProvider queryHandlerProvider;
private IManagedContainer container;
- private List<ReadAccessHandler> readAccessHandlers = new ArrayList<ReadAccessHandler>();
+ private final List<ReadAccessHandler> readAccessHandlers = new ArrayList<ReadAccessHandler>();
- private List<WriteAccessHandler> writeAccessHandlers = new ArrayList<WriteAccessHandler>();
-
- private EPackage[] initialPackages;
+ private final List<WriteAccessHandler> writeAccessHandlers = new ArrayList<WriteAccessHandler>();
// Bug 297940
- private TimeStampAuthority timeStampAuthority = new TimeStampAuthority(this);
-
- private long lastTreeRestructuringCommit = -1;
+ private final TimeStampAuthority timeStampAuthority = new TimeStampAuthority(this);
@ExcludeFromDump
- private transient Object commitTransactionLock = new Object();
+ private final transient Object commitTransactionLock = new Object();
@ExcludeFromDump
- private transient Object createBranchLock = new Object();
+ private final transient Object createBranchLock = new Object();
private boolean skipInitialization;
+ private EPackage[] initialPackages;
+
private CDOID rootResourceID;
+ private long lastTreeRestructuringCommit = -1;
+
public Repository()
{
}
@@ -355,6 +360,11 @@ public class Repository extends Container<Object>implements InternalRepository,
return supportingBranches;
}
+ public boolean isSupportingUnits()
+ {
+ return supportingUnits;
+ }
+
@Deprecated
public boolean isSupportingEcore()
{
@@ -972,6 +982,17 @@ public class Repository extends Container<Object>implements InternalRepository,
this.sessionManager = sessionManager;
}
+ public InternalUnitManager getUnitManager()
+ {
+ return unitManager;
+ }
+
+ public void setUnitManager(InternalUnitManager unitManager)
+ {
+ checkInactive();
+ this.unitManager = unitManager;
+ }
+
public InternalCDOBranchManager getBranchManager()
{
return branchManager;
@@ -1918,6 +1939,13 @@ public class Repository extends Container<Object>implements InternalRepository,
supportingBranches = store.getRevisionParallelism() == IStore.RevisionParallelism.BRANCHING;
}
+ // SUPPORTING_UNITS
+ String valueUnits = properties.get(Props.SUPPORTING_UNITS);
+ if (valueUnits != null)
+ {
+ supportingUnits = Boolean.valueOf(valueUnits);
+ }
+
// SERIALIZE_COMMITS
String valueCommits = properties.get(Props.SERIALIZE_COMMITS);
if (valueCommits != null)
@@ -2086,6 +2114,7 @@ public class Repository extends Container<Object>implements InternalRepository,
newPackageUnitsForRootResource.add(packageUnit);
}
}
+
return newPackageUnitsForRootResource.toArray(new InternalCDOPackageUnit[0]);
}
@@ -2152,7 +2181,7 @@ public class Repository extends Container<Object>implements InternalRepository,
checkState(queryManager, "queryManager"); //$NON-NLS-1$
checkState(commitInfoManager, "commitInfoManager"); //$NON-NLS-1$
checkState(commitManager, "commitManager"); //$NON-NLS-1$
- checkState(getLockingManager(), "lockingManager"); //$NON-NLS-1$
+ checkState(lockingManager, "lockingManager"); //$NON-NLS-1$
packageRegistry.setReplacingDescriptors(true);
packageRegistry.setPackageProcessor(this);
@@ -2167,7 +2196,7 @@ public class Repository extends Container<Object>implements InternalRepository,
commitInfoManager.setRepository(this);
commitInfoManager.setCommitInfoLoader(this);
commitManager.setRepository(this);
- getLockingManager().setRepository(this);
+ lockingManager.setRepository(this);
store.setRepository(this);
}
@@ -2199,6 +2228,11 @@ public class Repository extends Container<Object>implements InternalRepository,
LifecycleUtil.activate(commitManager);
LifecycleUtil.activate(queryHandlerProvider);
+ if (supportingUnits)
+ {
+ LifecycleUtil.activate(unitManager);
+ }
+
if (!skipInitialization)
{
long creationTime = store.getCreationTime();
@@ -2227,7 +2261,8 @@ public class Repository extends Container<Object>implements InternalRepository,
@Override
protected void doDeactivate() throws Exception
{
- LifecycleUtil.deactivate(getLockingManager());
+ LifecycleUtil.deactivate(unitManager);
+ LifecycleUtil.deactivate(lockingManager);
LifecycleUtil.deactivate(queryHandlerProvider);
LifecycleUtil.deactivate(commitManager);
LifecycleUtil.deactivate(commitInfoManager);
@@ -2293,6 +2328,11 @@ public class Repository extends Container<Object>implements InternalRepository,
setLockingManager(createLockManager());
}
+ if (getUnitManager() == null)
+ {
+ setUnitManager(createUnitManager());
+ }
+
super.doBeforeActivate();
}
@@ -2331,6 +2371,11 @@ public class Repository extends Container<Object>implements InternalRepository,
return new CommitManager();
}
+ protected InternalUnitManager createUnitManager()
+ {
+ return new UnitManager(this);
+ }
+
@Deprecated
protected InternalLockManager createLockManager()
{
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java
index 2e40085253..fe13338342 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java
@@ -51,6 +51,7 @@ import org.eclipse.emf.cdo.view.CDOFetchRuleManager;
import org.eclipse.emf.cdo.view.CDOInvalidationPolicy;
import org.eclipse.emf.cdo.view.CDORevisionPrefetchingPolicy;
import org.eclipse.emf.cdo.view.CDOStaleReferencePolicy;
+import org.eclipse.emf.cdo.view.CDOUnitManager;
import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.emf.internal.cdo.session.SessionUtil;
@@ -464,6 +465,11 @@ public class ServerCDOView extends AbstractCDOView implements org.eclipse.emf.cd
throw new UnsupportedOperationException();
}
+ public CDOUnitManager getUnitManager()
+ {
+ throw new UnsupportedOperationException();
+ }
+
/**
* @author Eike Stepper
*/
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
index 776eae1ed0..f0016a2b45 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
@@ -74,7 +74,7 @@ import java.util.concurrent.atomic.AtomicInteger;
/**
* @author Eike Stepper
*/
-public class Session extends Container<IView>implements InternalSession
+public class Session extends Container<IView> implements InternalSession
{
private InternalSessionManager manager;
@@ -402,7 +402,7 @@ public class Session extends Container<IView>implements InternalSession
public void collectContainedRevisions(InternalCDORevision revision, CDOBranchPoint branchPoint, int referenceChunk,
Set<CDOID> revisions, List<CDORevision> additionalRevisions)
{
- InternalCDORevisionManager revisionManager = getManager().getRepository().getRevisionManager();
+ InternalCDORevisionManager revisionManager = manager.getRepository().getRevisionManager();
for (EStructuralFeature feature : revision.getClassInfo().getAllPersistentFeatures())
{
// TODO Clarify feature maps
@@ -577,8 +577,10 @@ public class Session extends Container<IView>implements InternalSession
}
}
- private boolean hasSubscription(CDOID id, InternalView[] views)
+ private boolean isDeltaNeeded(CDOID id, InternalView[] views)
{
+ boolean supportingUnits = manager.getRepository().isSupportingUnits();
+
for (InternalView view : views)
{
try
@@ -587,6 +589,11 @@ public class Session extends Container<IView>implements InternalSession
{
return true;
}
+
+ if (supportingUnits && view.isInOpenUnit(id))
+ {
+ return true;
+ }
}
catch (Exception ex)
{
@@ -788,7 +795,7 @@ public class Session extends Container<IView>implements InternalSession
CDORevisionDelta revisionDelta = (CDORevisionDelta)changedObjects.get(index);
CDOID id = revisionDelta.getID();
- if (changes || hasSubscription(id, views))
+ if (changes || isDeltaNeeded(id, views))
{
if (permissionManager == null)
{
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java
index e87ac6a685..f2edc097f3 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java
@@ -1322,7 +1322,7 @@ public class TransactionCommitContext implements InternalCommitContext
}
}
- protected IStoreAccessor getAccessor()
+ public IStoreAccessor getAccessor()
{
return accessor;
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/UnitManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/UnitManager.java
new file mode 100644
index 0000000000..d70f14681c
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/UnitManager.java
@@ -0,0 +1,734 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.internal.server;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.common.revision.CDORevisionProvider;
+import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
+import org.eclipse.emf.cdo.common.util.CDOException;
+import org.eclipse.emf.cdo.server.IStoreAccessor.UnitSupport;
+import org.eclipse.emf.cdo.server.IUnit;
+import org.eclipse.emf.cdo.server.IUnitManager;
+import org.eclipse.emf.cdo.server.IView;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.cdo.spi.server.InternalCommitContext;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
+import org.eclipse.emf.cdo.spi.server.InternalUnitManager;
+import org.eclipse.emf.cdo.spi.server.InternalView;
+
+import org.eclipse.net4j.util.container.Container;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+
+/**
+ * @author Eike Stepper
+ */
+public class UnitManager extends Container<IUnit> implements InternalUnitManager
+{
+ private final InternalRepository repository;
+
+ private final Map<CDOID, IUnit> units = CDOIDUtil.createMap();
+
+ private final Map<CDOID, UnitInitializer> unitInitializers = CDOIDUtil.createMap();
+
+ private final Set<ObjectAttacher> objectAttachers = new HashSet<ObjectAttacher>();
+
+ private final ReentrantReadWriteLock managerLock = new ReentrantReadWriteLock();
+
+ public UnitManager(InternalRepository repository)
+ {
+ this.repository = repository;
+ }
+
+ public final InternalRepository getRepository()
+ {
+ return repository;
+ }
+
+ public boolean isUnit(CDOID rootID)
+ {
+ checkActive();
+
+ ReadLock readLock = managerLock.readLock();
+ readLock.lock();
+
+ try
+ {
+ // No need to synchronize on units because all other modifiers hold the manager write lock.
+ return units.containsKey(rootID);
+ }
+ finally
+ {
+ readLock.unlock();
+ }
+ }
+
+ public IUnit createUnit(CDOID rootID, IView view, CDORevisionHandler revisionHandler)
+ {
+ checkActive();
+
+ WriteLock writeLock = managerLock.writeLock();
+ UnitInitializer unitInitializer;
+ boolean hook = false;
+
+ ////////////////////////////////////
+ // Phase 1: Register (short, locked)
+ ////////////////////////////////////
+
+ writeLock.lock();
+
+ try
+ {
+ createUnitHook1();
+
+ // No need to synchronize on units because all other access holds the manager lock.
+ if (units.containsKey(rootID))
+ {
+ return null;
+ }
+
+ // No need to synchronize on unitInitializers because all other access holds the manager lock.
+ unitInitializer = unitInitializers.get(rootID);
+ if (unitInitializer != null)
+ {
+ hook = true;
+ }
+ else
+ {
+ checkNotNested(rootID, view, units.keySet());
+ checkNotNested(rootID, view, unitInitializers.keySet());
+
+ unitInitializer = createUnitInitializer(rootID, view, revisionHandler);
+
+ // No need to synchronize on unitInitializers because all other access holds the manager lock.
+ unitInitializers.put(rootID, unitInitializer);
+
+ // Synchronize on objectAttachers because objectAttacherFinishedCommit() doesn't acquire the manager lock!
+ synchronized (objectAttachers)
+ {
+ for (ObjectAttacher objectAttacher : objectAttachers)
+ {
+ List<CDOID> ids = objectAttacher.removeUnmappedRevisionsFor(unitInitializer);
+ if (!ids.isEmpty())
+ {
+ unitInitializer.addObjectAttacher(objectAttacher, ids);
+ }
+ }
+ }
+ }
+ }
+ finally
+ {
+ writeLock.unlock();
+ }
+
+ if (hook)
+ {
+ return unitInitializer.hook(rootID, view, revisionHandler);
+ }
+
+ IUnit unit = null;
+
+ try
+ {
+ /////////////////////////////////////////////////////
+ // Phase 2: Initialize (potentially long, not locked)
+ /////////////////////////////////////////////////////
+
+ unit = unitInitializer.initialize();
+ }
+ finally
+ {
+ ///////////////////////////////////
+ // Phase 3: Publish (short, locked)
+ ///////////////////////////////////
+
+ try
+ {
+ writeLock.lock();
+
+ try
+ {
+ // No need to synchronize on unitInitializers because all other access holds the manager lock.
+ unitInitializers.remove(rootID);
+
+ if (unit != null)
+ {
+ // No need to synchronize on units because all other access holds the manager lock.
+ units.put(rootID, unit);
+ }
+ }
+ finally
+ {
+ writeLock.unlock();
+ }
+ }
+ finally
+ {
+ unitInitializer.notifyHookedInitializers();
+ }
+ }
+
+ fireElementAddedEvent(unit);
+ return unit;
+ }
+
+ private void checkNotNested(CDOID rootID, IView view, Set<CDOID> unitIDs)
+ {
+ InternalCDORevision rootRevision = (InternalCDORevision)view.getRevision(rootID);
+ CDOID unitID = getUnit(rootRevision, view, unitIDs);
+ if (unitID != null)
+ {
+ throw new CDOException("Attempt to nest the new unit " + rootID + " in the existing unit " + unitID);
+ }
+
+ Set<CDOID> set = Collections.singleton(rootID);
+ for (CDOID id : unitIDs)
+ {
+ InternalCDORevision revision = (InternalCDORevision)view.getRevision(id);
+ if (getUnit(revision, view, set) != null)
+ {
+ throw new CDOException("Attempt to nest the existing unit " + id + " in the new unit " + rootID);
+ }
+ }
+ }
+
+ public IUnit getUnit(CDOID rootID)
+ {
+ checkActive();
+
+ ReadLock readLock = managerLock.readLock();
+ readLock.lock();
+
+ try
+ {
+ // No need to synchronize on units because all other modifiers hold the manager write lock.
+ return units.get(rootID);
+ }
+ finally
+ {
+ readLock.unlock();
+ }
+ }
+
+ public IUnit[] getUnits()
+ {
+ checkActive();
+ return getElements();
+ }
+
+ public IUnit[] getElements()
+ {
+ ReadLock readLock = managerLock.readLock();
+ readLock.lock();
+
+ try
+ {
+ // No need to synchronize on units because all other modifiers hold the manager write lock.
+ return units.values().toArray(new IUnit[units.size()]);
+ }
+ finally
+ {
+ readLock.unlock();
+ }
+ }
+
+ public InternalObjectAttacher attachObjects(InternalCommitContext commitContext)
+ {
+ checkActive();
+
+ long timeStamp = commitContext.getTimeStamp();
+
+ ObjectAttacher objectAttacher = null;
+ Map<CDOID, CDOID> unitMappings = CDOIDUtil.createMap();
+
+ ///////////////////////////////////////////////
+ // Phase 1: Analyze new objects (short, locked)
+ ///////////////////////////////////////////////
+
+ ReadLock readLock = managerLock.readLock();
+ readLock.lock();
+
+ try
+ {
+ attachObjectsHook1();
+
+ Set<CDOID> rootIDs = new HashSet<CDOID>();
+
+ // No need to synchronize on units because all other modifiers hold the manager write lock.
+ rootIDs.addAll(units.keySet());
+
+ // No need to synchronize on unitInitializers because all other modifiers hold the manager write lock.
+ rootIDs.addAll(unitInitializers.keySet());
+
+ List<InternalCDORevision> unmappedRevisions = new ArrayList<InternalCDORevision>();
+ boolean checkUnits = !rootIDs.isEmpty();
+
+ for (InternalCDORevision revision : commitContext.getNewObjects())
+ {
+ if (checkUnits)
+ {
+ CDOID rootID = getUnit(revision, commitContext, rootIDs);
+ if (rootID != null)
+ {
+ unitMappings.put(revision.getID(), rootID);
+ continue;
+ }
+ }
+
+ unmappedRevisions.add(revision);
+ }
+
+ if (!unmappedRevisions.isEmpty())
+ {
+ objectAttacher = createObjectAttacher(commitContext, unmappedRevisions);
+
+ // Read lock holders must synchronize modifications of the private collections.
+ synchronized (objectAttachers)
+ {
+ objectAttachers.add(objectAttacher);
+ }
+ }
+ }
+ finally
+ {
+ readLock.unlock();
+ }
+
+ //////////////////////////////////////////////////////////
+ // Phase 2: Map objects to existing units (long, unlocked)
+ //////////////////////////////////////////////////////////
+
+ if (!unitMappings.isEmpty())
+ {
+ mapAttachedObjectsToUnits(commitContext, timeStamp, unitMappings);
+ }
+
+ return objectAttacher;
+ }
+
+ /**
+ * Does not hold any manager lock when called.
+ */
+ public void objectAttacherFinishedCommit(ObjectAttacher objectAttacher)
+ {
+ checkActive();
+
+ synchronized (objectAttachers)
+ {
+ objectAttachers.remove(objectAttacher);
+ }
+ }
+
+ @Override
+ protected void doActivate() throws Exception
+ {
+ super.doActivate();
+
+ UnitSupport storeAccessor = (UnitSupport)repository.getStore().getReader(null);
+
+ try
+ {
+ List<CDOID> roots = storeAccessor.readUnitRoots();
+ for (CDOID root : roots)
+ {
+ IUnit unit = createUnit(root);
+
+ // No need to synchronize on units because all other access call checkActive()
+ units.put(root, unit);
+ }
+ }
+ finally
+ {
+ storeAccessor.release();
+ }
+ }
+
+ @Override
+ protected void doDeactivate() throws Exception
+ {
+ // No need to synchronize on units because all other access call checkActive()
+ units.clear();
+
+ super.doDeactivate();
+ }
+
+ protected Unit createUnit(CDOID root)
+ {
+ return new Unit(root);
+ }
+
+ protected UnitInitializer createUnitInitializer(CDOID rootID, IView view, CDORevisionHandler revisionHandler)
+ {
+ return new UnitInitializer(rootID, view, revisionHandler);
+ }
+
+ protected ObjectAttacher createObjectAttacher(InternalCommitContext commitContext,
+ List<InternalCDORevision> unmappedRevisions)
+ {
+ return new ObjectAttacher(commitContext, unmappedRevisions);
+ }
+
+ protected void mapAttachedObjectsToUnits(InternalCommitContext commitContext, long timeStamp,
+ Map<CDOID, CDOID> unitMappings)
+ {
+ UnitSupport storeAccessor = (UnitSupport)commitContext.getAccessor();
+ storeAccessor.writeUnits(unitMappings, timeStamp);
+ }
+
+ protected void createUnitHook1()
+ {
+ }
+
+ protected void attachObjectsHook1()
+ {
+ }
+
+ private static CDOID getUnit(InternalCDORevision revision, CDORevisionProvider revisionProvider, Set<CDOID> rootIDs)
+ {
+ if (rootIDs.isEmpty())
+ {
+ return null;
+ }
+
+ CDOID id = revision.getID();
+ if (rootIDs.contains(id))
+ {
+ return id;
+ }
+
+ CDORevision parentRevision = CDORevisionUtil.getParentRevision(revision, revisionProvider);
+ if (parentRevision != null)
+ {
+ return getUnit((InternalCDORevision)parentRevision, revisionProvider, rootIDs);
+ }
+
+ return null;
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ protected class Unit implements IUnit
+ {
+ private final CDOID rootID;
+
+ private final Set<IView> views = new HashSet<IView>();
+
+ public Unit(CDOID rootID)
+ {
+ this.rootID = rootID;
+ }
+
+ public IUnitManager getManager()
+ {
+ return UnitManager.this;
+ }
+
+ public CDOID getRootID()
+ {
+ return rootID;
+ }
+
+ public boolean isOpen()
+ {
+ synchronized (views)
+ {
+ return !views.isEmpty();
+ }
+ }
+
+ public void open(IView view, final CDORevisionHandler revisionHandler)
+ {
+ synchronized (views)
+ {
+ views.add(view);
+ }
+
+ UnitSupport storeAccessor = (UnitSupport)repository.getStore().getReader(null);
+
+ try
+ {
+ storeAccessor.readUnit(view, rootID, revisionHandler);
+ }
+ finally
+ {
+ storeAccessor.release();
+ }
+ }
+
+ public void close(IView view)
+ {
+ synchronized (views)
+ {
+ views.remove(view);
+ }
+
+ ((InternalView)view).closeUnit(rootID);
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Unit[" + rootID + "]";
+ }
+
+ /**
+ * Does not hold any manager lock when called.
+ */
+ public void initialize(IView view, long timeStamp, CDORevisionHandler revisionHandler,
+ Map<ObjectAttacher, List<CDOID>> objectAttachers)
+ {
+ UnitSupport storeAccessor = (UnitSupport)repository.getStore().getWriter(null);
+
+ try
+ {
+ Set<CDOID> initializedIDs = new HashSet<CDOID>();
+ Object initResult = storeAccessor.initUnit(view, rootID, revisionHandler, initializedIDs, timeStamp);
+
+ List<CDOID> ids = new ArrayList<CDOID>();
+ for (Entry<ObjectAttacher, List<CDOID>> entry : objectAttachers.entrySet())
+ {
+ ObjectAttacher objectAttacher = entry.getKey();
+ if (objectAttacher.awaitFinishedCommit())
+ {
+ for (CDOID id : entry.getValue())
+ {
+ if (!initializedIDs.contains(id))
+ {
+ ids.add(id);
+ }
+ }
+ }
+ }
+
+ storeAccessor.finishUnit(view, rootID, revisionHandler, timeStamp, initResult, ids);
+ }
+ finally
+ {
+ storeAccessor.release();
+ }
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ protected class UnitInitializer implements CDORevisionHandler
+ {
+ private final long timeStamp = repository.getTimeStamp();
+
+ private final Map<ObjectAttacher, List<CDOID>> concurrentObjectAttachers = new HashMap<ObjectAttacher, List<CDOID>>();
+
+ private final CountDownLatch unitInitialized = new CountDownLatch(1);
+
+ private final CDOID rootID;
+
+ private final IView view;
+
+ private final CDORevisionHandler revisionHandler;
+
+ private final List<CDORevisionHandler> hookedRevisionHandlers = new CopyOnWriteArrayList<CDORevisionHandler>();
+
+ private volatile boolean hasHookedRevisionHandlers;
+
+ private Unit unit;
+
+ public UnitInitializer(CDOID rootID, IView view, CDORevisionHandler revisionHandler)
+ {
+ this.rootID = rootID;
+ this.view = view;
+ this.revisionHandler = revisionHandler;
+ }
+
+ public CDOID getRootID()
+ {
+ return rootID;
+ }
+
+ /**
+ * Does not hold any manager lock when called.
+ */
+ public IUnit initialize()
+ {
+ unit = new Unit(rootID);
+ unit.initialize(view, timeStamp, revisionHandler, concurrentObjectAttachers);
+ return unit;
+ }
+
+ /**
+ * Does not hold any manager lock when called.
+ */
+ public IUnit hook(CDOID rootID, IView view, final CDORevisionHandler revisionHandler)
+ {
+ final Set<CDOID> ids = new HashSet<CDOID>();
+
+ hookedRevisionHandlers.add(new CDORevisionHandler()
+ {
+ public boolean handleRevision(CDORevision revision)
+ {
+ ids.add(revision.getID());
+ return revisionHandler.handleRevision(revision);
+ }
+ });
+
+ // It's okay to do this unsynchronized. The worst thing that could happen is that the hooked revision handler is
+ // missed a few times during UnitInitializer.handleRevision(), but that's okay because it probably missed many
+ // revisions already and therefore performs an openUnit() subsequently, anyways. After all, hooked revision
+ // handlers,
+ // i.e., concurrent createUnit() calls for the same unit, are extremely rare.
+ hasHookedRevisionHandlers = true;
+
+ try
+ {
+ // Now wait for the main revision handler to finish.
+ unitInitialized.await();
+ }
+ catch (InterruptedException ex)
+ {
+ return null;
+ }
+
+ // Now send the missed revisions.
+ unit.open(view, new CDORevisionHandler()
+ {
+ public boolean handleRevision(CDORevision revision)
+ {
+ if (ids.contains(revision.getID()))
+ {
+ // This revision has already been sent. Skip to the next one.
+ return true;
+ }
+
+ return revisionHandler.handleRevision(revision);
+ }
+ });
+
+ return unit;
+ }
+
+ /**
+ * Does not hold any manager lock when called.
+ */
+ public void notifyHookedInitializers()
+ {
+ unitInitialized.countDown();
+ }
+
+ public boolean handleRevision(CDORevision revision)
+ {
+ if (revisionHandler.handleRevision(revision))
+ {
+ if (hasHookedRevisionHandlers)
+ {
+ for (CDORevisionHandler hookedRevisionHandler : hookedRevisionHandlers)
+ {
+ hookedRevisionHandler.handleRevision(revision);
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Holds the manager write lock when called.
+ */
+ public void addObjectAttacher(ObjectAttacher objectAttacher, List<CDOID> ids)
+ {
+ concurrentObjectAttachers.put(objectAttacher, ids);
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ protected class ObjectAttacher implements InternalObjectAttacher
+ {
+ private final InternalCommitContext commitContext;
+
+ private final List<InternalCDORevision> unmappedRevisions;
+
+ private final CountDownLatch commitFinished = new CountDownLatch(1);
+
+ private boolean commitSucceeded;
+
+ public ObjectAttacher(InternalCommitContext commitContext, List<InternalCDORevision> unmappedRevisions)
+ {
+ this.commitContext = commitContext;
+ this.unmappedRevisions = unmappedRevisions;
+ }
+
+ /**
+ * Does not hold any manager lock when called.
+ */
+ public void finishedCommit(boolean success)
+ {
+ objectAttacherFinishedCommit(this);
+
+ commitSucceeded = success;
+ commitFinished.countDown();
+ }
+
+ /**
+ * Holds the manager write lock when called.
+ */
+ public List<CDOID> removeUnmappedRevisionsFor(UnitInitializer unitInitializer)
+ {
+ List<CDOID> ids = new ArrayList<CDOID>();
+
+ Set<CDOID> rootIDs = Collections.singleton(unitInitializer.getRootID());
+ for (Iterator<InternalCDORevision> it = unmappedRevisions.iterator(); it.hasNext();)
+ {
+ InternalCDORevision revision = it.next();
+ if (getUnit(revision, commitContext, rootIDs) != null)
+ {
+ ids.add(revision.getID());
+ it.remove();
+ }
+ }
+
+ return ids;
+ }
+
+ public boolean awaitFinishedCommit()
+ {
+ try
+ {
+ commitFinished.await();
+ }
+ catch (InterruptedException ex)
+ {
+ return false;
+ }
+
+ return commitSucceeded;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java
index 9b3f19187a..3ff8d9c950 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/View.java
@@ -15,9 +15,13 @@ import org.eclipse.emf.cdo.common.CDOCommonView;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
import org.eclipse.emf.cdo.common.revision.CDORevisionManager;
import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
+import org.eclipse.emf.cdo.server.IUnit;
+import org.eclipse.emf.cdo.server.IUnitManager;
import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil;
import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
@@ -57,9 +61,11 @@ public class View extends Lifecycle implements InternalView, CDOCommonView.Optio
private String durableLockingID;
- private InternalRepository repository;
+ private final InternalRepository repository;
- private Set<CDOID> changeSubscriptionIDs = new HashSet<CDOID>();
+ private final Set<CDOID> changeSubscriptionIDs = new HashSet<CDOID>();
+
+ private final Set<CDOID> openUnitRoots = new HashSet<CDOID>();
private boolean lockNotificationsEnabled;
@@ -155,7 +161,7 @@ public class View extends Lifecycle implements InternalView, CDOCommonView.Optio
List<CDORevision> oldRevisions = getRevisions(invalidObjects);
setBranchPoint(branchPoint);
List<CDORevision> newRevisions = getRevisions(invalidObjects);
-
+
Iterator<CDORevision> it = newRevisions.iterator();
for (CDORevision oldRevision : oldRevisions)
{
@@ -169,7 +175,7 @@ public class View extends Lifecycle implements InternalView, CDOCommonView.Optio
// Fix for Bug 369646: ensure that revisions are fully loaded
repository.ensureChunks((InternalCDORevision)newRevision, CDORevision.UNCHUNKED);
repository.ensureChunks((InternalCDORevision)oldRevision, CDORevision.UNCHUNKED);
-
+
CDORevisionDelta delta = newRevision.compare(oldRevision);
allChangedObjects.add(delta);
}
@@ -199,6 +205,66 @@ public class View extends Lifecycle implements InternalView, CDOCommonView.Optio
this.durableLockingID = durableLockingID;
}
+ public boolean openUnit(CDOID rootID, boolean create, CDORevisionHandler revisionHandler)
+ {
+ IUnitManager unitManager = repository.getUnitManager();
+ IUnit unit = unitManager.getUnit(rootID);
+
+ if (create)
+ {
+ if (unit != null)
+ {
+ return false;
+ }
+
+ unit = unitManager.createUnit(rootID, this, revisionHandler);
+ }
+ else
+ {
+ if (unit == null)
+ {
+ return false;
+ }
+
+ unit.open(this, revisionHandler);
+ }
+
+ openUnitRoots.add(rootID);
+ return true;
+ }
+
+ public void closeUnit(CDOID rootID)
+ {
+ openUnitRoots.remove(rootID);
+ }
+
+ public boolean isInOpenUnit(CDOID id)
+ {
+ if (openUnitRoots.isEmpty())
+ {
+ return false;
+ }
+
+ if (openUnitRoots.contains(id))
+ {
+ return true;
+ }
+
+ InternalCDORevision revision = getRevision(id);
+ if (revision != null)
+ {
+ CDOID parentID = revision.getResourceID();
+ if (CDOIDUtil.isNull(parentID))
+ {
+ parentID = (CDOID)revision.getContainerID();
+ }
+
+ return isInOpenUnit(parentID);
+ }
+
+ return false;
+ }
+
/**
* @since 2.0
*/
@@ -227,7 +293,12 @@ public class View extends Lifecycle implements InternalView, CDOCommonView.Optio
return false;
}
- return changeSubscriptionIDs.contains(id);
+ if (changeSubscriptionIDs.contains(id))
+ {
+ return true;
+ }
+
+ return false;
}
/**
@@ -288,6 +359,7 @@ public class View extends Lifecycle implements InternalView, CDOCommonView.Optio
public void doClose()
{
clearChangeSubscription();
+ openUnitRoots.clear();
closed = true;
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedClientSessionProtocol.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedClientSessionProtocol.java
index 75db50bbc4..8912da605e 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedClientSessionProtocol.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/embedded/EmbeddedClientSessionProtocol.java
@@ -653,6 +653,11 @@ public class EmbeddedClientSessionProtocol extends Lifecycle implements CDOSessi
throw new UnsupportedOperationException();
}
+ public boolean requestUnit(int viewID, CDOID rootID, byte opcode, CDORevisionHandler revisionHandler)
+ {
+ throw new UnsupportedOperationException();
+ }
+
@Override
protected void doActivate() throws Exception
{
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IRepository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IRepository.java
index 738ee52aff..5de431d616 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IRepository.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IRepository.java
@@ -86,6 +86,11 @@ public interface IRepository extends CDOCommonRepository, IQueryHandlerProvider,
public ISessionManager getSessionManager();
/**
+ * @since 4.5
+ */
+ public IUnitManager getUnitManager();
+
+ /**
* @since 4.0
* @deprecated As of 4.1 use {@link #getLockingManager()}.
*/
@@ -319,6 +324,11 @@ public interface IRepository extends CDOCommonRepository, IQueryHandlerProvider,
public static final String SUPPORTING_BRANCHES = "supportingBranches"; //$NON-NLS-1$
/**
+ * @since 4.5
+ */
+ public static final String SUPPORTING_UNITS = "supportingUnits"; //$NON-NLS-1$
+
+ /**
* @since 4.0
* @deprecated As of 4.2 instances of Ecore are always supported (on demand).
*/
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java
index 62059a2667..a2cc5da856 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IStoreAccessor.java
@@ -798,4 +798,26 @@ public interface IStoreAccessor extends IQueryHandlerProvider, BranchLoader, Com
public void updateLockArea(LockArea lockArea);
}
+
+ /**
+ * An extension interface for {@link IStoreAccessor store accessors} that support <i>units</i>.
+ *
+ * @author Eike Stepper
+ * @since 4.5
+ * @apiviz.exclude
+ */
+ public interface UnitSupport extends IStoreAccessor
+ {
+ public List<CDOID> readUnitRoots();
+
+ public void readUnit(IView view, CDOID rootID, CDORevisionHandler revisionHandler);
+
+ public Object initUnit(IView view, CDOID rootID, CDORevisionHandler revisionHandler, Set<CDOID> initializedIDs,
+ long timeStamp);
+
+ public void finishUnit(IView view, CDOID rootID, CDORevisionHandler revisionHandler, long timeStamp,
+ Object initResult, List<CDOID> ids);
+
+ public void writeUnits(Map<CDOID, CDOID> unitMappings, long timeStamp);
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IUnit.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IUnit.java
new file mode 100644
index 0000000000..be18cfa165
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IUnit.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+
+/**
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @author Eike Stepper
+ * @since 4.5
+ */
+public interface IUnit
+{
+ public IUnitManager getManager();
+
+ public CDOID getRootID();
+
+ public boolean isOpen();
+
+ public void open(IView view, CDORevisionHandler revisionHandler);
+
+ public void close(IView view);
+}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IUnitManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IUnitManager.java
new file mode 100644
index 0000000000..15523d76e9
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IUnitManager.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+
+import org.eclipse.net4j.util.container.IContainer;
+
+/**
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @author Eike Stepper
+ * @since 4.5
+ */
+public interface IUnitManager extends IContainer<IUnit>
+{
+ public IRepository getRepository();
+
+ public IUnit createUnit(CDOID rootID, IView view, CDORevisionHandler revisionHandler);
+
+ public boolean isUnit(CDOID rootID);
+
+ public IUnit getUnit(CDOID rootID);
+
+ public IUnit[] getUnits();
+}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalCommitContext.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalCommitContext.java
index d304a713df..f911de3243 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalCommitContext.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalCommitContext.java
@@ -67,6 +67,11 @@ public interface InternalCommitContext extends IStoreAccessor.CommitContext, CDO
public InternalTransaction getTransaction();
/**
+ * @since 4.5
+ */
+ public IStoreAccessor getAccessor();
+
+ /**
* @since 4.2
*/
public long getTimeStamp();
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java
index c86b01b557..7c0a55c9bd 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalRepository.java
@@ -116,6 +116,16 @@ public interface InternalRepository extends IRepository, PackageProcessor, Packa
*/
public InternalLockManager getLockingManager();
+ /**
+ * @since 4.5
+ */
+ public InternalUnitManager getUnitManager();
+
+ /**
+ * @since 4.5
+ */
+ public void setUnitManager(InternalUnitManager unitManager);
+
public InternalQueryManager getQueryManager();
public void setQueryHandlerProvider(IQueryHandlerProvider queryHandlerProvider);
@@ -262,6 +272,11 @@ public interface InternalRepository extends IRepository, PackageProcessor, Packa
public void setSkipInitialization(boolean skipInitialization);
/**
+ * @since 4.5
+ */
+ public boolean isSupportingUnits();
+
+ /**
* @since 4.0
* @deprecated As of 4.3 use {@link #initSystemPackages()}.
*/
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalUnitManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalUnitManager.java
new file mode 100644
index 0000000000..731ffbfc01
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalUnitManager.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.spi.server;
+
+import org.eclipse.emf.cdo.server.IUnitManager;
+
+/**
+ * @author Eike Stepper
+ * @since 4.5
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+*/
+public interface InternalUnitManager extends IUnitManager
+{
+ public InternalRepository getRepository();
+
+ public InternalObjectAttacher attachObjects(InternalCommitContext commitContext);
+
+ /**
+ * @author Eike Stepper
+ */
+ public interface InternalObjectAttacher
+ {
+ public void finishedCommit(boolean success);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java
index f6e8857176..d140229147 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalView.java
@@ -12,6 +12,7 @@ package org.eclipse.emf.cdo.spi.server;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
import org.eclipse.emf.cdo.server.IView;
@@ -55,4 +56,19 @@ public interface InternalView extends IView, ILifecycle
public void clearChangeSubscription();
public void doClose();
+
+ /**
+ * @since 4.5
+ */
+ public boolean openUnit(CDOID rootID, boolean create, CDORevisionHandler revisionHandler);
+
+ /**
+ * @since 4.5
+ */
+ public void closeUnit(CDOID rootID);
+
+ /**
+ * @since 4.5
+ */
+ public boolean isInOpenUnit(CDOID id);
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/Store.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/Store.java
index 931a4b75c1..ca55a80ea4 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/Store.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/Store.java
@@ -400,7 +400,12 @@ public abstract class Store extends Lifecycle implements InternalStore
{
CDORevisionFactory factory = repository.getRevisionManager().getFactory();
InternalCDORevision revision = (InternalCDORevision)factory.createRevision(eClass);
- revision.setID(id);
+
+ if (id != null)
+ {
+ revision.setID(id);
+ }
+
return revision;
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java
index 0ff8592ca5..1cdbe40908 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessor.java
@@ -95,7 +95,7 @@ public abstract class StoreAccessor extends StoreAccessorBase
if (newObjects.length != 0)
{
- writeRevisions(newObjects, branch, monitor.fork(newObjects.length));
+ writeNewObjectRevisions(context, newObjects, branch, monitor.fork(newObjects.length));
}
if (dirtyCount != 0)
@@ -106,7 +106,7 @@ public abstract class StoreAccessor extends StoreAccessorBase
}
else
{
- writeRevisions(dirtyObjects, branch, monitor.fork(dirtyCount));
+ writeDirtyObjectRevisions(context, dirtyObjects, branch, monitor.fork(dirtyCount));
}
}
@@ -167,6 +167,24 @@ public abstract class StoreAccessor extends StoreAccessorBase
String comment, OMMonitor monitor);
/**
+ * @since 4.5
+ */
+ protected void writeNewObjectRevisions(InternalCommitContext context, InternalCDORevision[] newObjects,
+ CDOBranch branch, OMMonitor monitor)
+ {
+ writeRevisions(newObjects, branch, monitor);
+ }
+
+ /**
+ * @since 4.5
+ */
+ protected void writeDirtyObjectRevisions(InternalCommitContext context, InternalCDORevision[] dirtyObjects,
+ CDOBranch branch, OMMonitor monitor)
+ {
+ writeRevisions(dirtyObjects, branch, monitor);
+ }
+
+ /**
* @since 3.0
*/
protected abstract void writeRevisions(InternalCDORevision[] revisions, CDOBranch branch, OMMonitor monitor);
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/CDO AllTests (H2 audit).launch b/plugins/org.eclipse.emf.cdo.tests.db/CDO AllTests (H2 audit).launch
index d00e13136c..b3a9432737 100644
--- a/plugins/org.eclipse.emf.cdo.tests.db/CDO AllTests (H2 audit).launch
+++ b/plugins/org.eclipse.emf.cdo.tests.db/CDO AllTests (H2 audit).launch
@@ -12,5 +12,5 @@
<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit3"/>
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.emf.cdo.tests.db.AllTestsDBH2Audit"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.emf.cdo.tests.db"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms40m&#13;&#10;-Xmx1024m&#13;&#10;-Dorg.eclipse.net4j.util.om.trace.disable=true"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1G&#13;&#10;-Xmx4G&#13;&#10;-Dorg.eclipse.net4j.util.om.trace.disable=true&#13;&#10;-Dorg.eclipse.emf.cdo.tests.config.impl.RepositoryConfig.enableServerBrowser=true"/>
</launchConfiguration>
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/MysqlConfig.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/MysqlConfig.java
index 82f69fb120..d4185a5e8b 100644
--- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/MysqlConfig.java
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/MysqlConfig.java
@@ -35,9 +35,11 @@ public class MysqlConfig extends AbstractSetupDBConfig
*/
public static final String HOST = "localhost";
- public static final String USER = "root";
+ public static final String SCHEMA = "test";
- public static final String PASS = "root";
+ public static final String USER = "test";
+
+ public static final String PASS = "0000";
private static final long serialVersionUID = 1L;
@@ -62,7 +64,7 @@ public class MysqlConfig extends AbstractSetupDBConfig
protected DataSource createDataSourceForDB(String dbName) throws SQLException
{
MysqlDataSource dataSource = new MysqlDataSource();
- dataSource.setUrl("jdbc:mysql://" + HOST);
+ dataSource.setUrl("jdbc:mysql://" + HOST + "/" + SCHEMA);
dataSource.setUser(USER);
if (PASS != null)
{
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
index 1598df139e..419531a15d 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllConfigs.java
@@ -116,7 +116,7 @@ public class AllConfigs extends ConfigTestSuite
testClasses.add(WorkspaceTest.class);
testClasses.add(BackupTest.class);
testClasses.add(ResourceModificationTrackingTest.class);
- testClasses.add(CDOStaleReferencePolicyTests.class);
+ testClasses.add(CDOStaleReferencePolicyTest.class);
// TODO testClasses.add(RemoteSessionManagerTest.class);
// TODO testClasses.add(NonCDOResourceTest.class);
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOStaleReferencePolicyTests.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOStaleReferencePolicyTest.java
index 56500ab5a3..9d4634c2ea 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOStaleReferencePolicyTests.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CDOStaleReferencePolicyTest.java
@@ -29,7 +29,7 @@ import org.eclipse.emf.ecore.util.EcoreUtil;
*
* @author Esteban Dugueperoux
*/
-public class CDOStaleReferencePolicyTests extends AbstractCDOTest
+public class CDOStaleReferencePolicyTest extends AbstractCDOTest
{
private static final String RESOURCE_NAME = "test1.model1";
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java
index 352c77c0c6..6f9f3f209e 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java
@@ -50,6 +50,7 @@ import org.eclipse.emf.spi.cdo.InternalCDOSession;
import java.util.Collection;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* @author Eike Stepper
@@ -234,7 +235,7 @@ public class SessionTest extends AbstractCDOTest
{
try
{
- startLatch.await();
+ startLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
msg("Committing NOW!");
commitTime[0] = transaction.commit().getTimeStamp();
@@ -251,7 +252,7 @@ public class SessionTest extends AbstractCDOTest
CDOSession session2 = openSession();
startLatch.countDown();
- stopLatch.await();
+ stopLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
assertEquals(true, session2.waitForUpdate(commitTime[0], DEFAULT_TIMEOUT));
transaction.getSession().close();
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/UnitManagerMain.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/UnitManagerMain.java
new file mode 100644
index 0000000000..33e8c17d58
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/UnitManagerMain.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests;
+
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.net4j.CDONet4jSessionConfiguration;
+import org.eclipse.emf.cdo.net4j.CDONet4jUtil;
+import org.eclipse.emf.cdo.server.net4j.CDONet4jServerUtil;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.model1.Category;
+import org.eclipse.emf.cdo.tests.model1.Company;
+import org.eclipse.emf.cdo.tests.model1.Customer;
+import org.eclipse.emf.cdo.tests.model1.Model1Factory;
+import org.eclipse.emf.cdo.tests.model1.Model1Package;
+import org.eclipse.emf.cdo.tests.model1.OrderDetail;
+import org.eclipse.emf.cdo.tests.model1.Product1;
+import org.eclipse.emf.cdo.tests.model1.PurchaseOrder;
+import org.eclipse.emf.cdo.tests.model1.SalesOrder;
+import org.eclipse.emf.cdo.tests.model1.Supplier;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+
+import org.eclipse.net4j.Net4jUtil;
+import org.eclipse.net4j.connector.IConnector;
+import org.eclipse.net4j.tcp.TCPUtil;
+import org.eclipse.net4j.util.container.IPluginContainer;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.InternalEList;
+
+import java.util.Iterator;
+
+/**
+ * @author Eike Stepper
+ */
+public class UnitManagerMain
+{
+ private static final String RESOURCE_NAME = "test";
+
+ private static final boolean ADD_UNIQUE = true;
+
+ private static long start;
+
+ /**
+ * @author Eike Stepper
+ */
+ public static final class FillRepository
+ {
+ public static void main(String[] args) throws Exception
+ {
+ CDOSession session = openSession();
+
+ try
+ {
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(RESOURCE_NAME);
+
+ for (int i = 0; i < 1; i++)
+ {
+ start("Fill " + i);
+ Company company = Model1Factory.eINSTANCE.createCompany();
+ add(resource.getContents(), company);
+ fillCompany(company);
+ stop();
+
+ start("Commit " + i);
+ transaction.commit();
+ stop();
+ }
+ }
+ finally
+ {
+ session.close();
+ }
+ }
+
+ private static void fillCompany(Company company)
+ {
+ for (int i = 0; i < 5; i++)
+ {
+ Category category = Model1Factory.eINSTANCE.createCategory();
+ add(company.getCategories(), category);
+ fillCategory(category, 5);
+ }
+
+ for (int i = 0; i < 1000; i++)
+ {
+ Supplier supplier = Model1Factory.eINSTANCE.createSupplier();
+ add(company.getSuppliers(), supplier);
+ }
+
+ for (int i = 0; i < 1000; i++)
+ {
+ Customer customer = Model1Factory.eINSTANCE.createCustomer();
+ add(company.getCustomers(), customer);
+ }
+
+ for (int i = 0; i < 1000; i++)
+ {
+ PurchaseOrder order = Model1Factory.eINSTANCE.createPurchaseOrder();
+ order.setSupplier(company.getSuppliers().get(i));
+ add(company.getPurchaseOrders(), order);
+
+ for (int j = 0; j < 100; j++)
+ {
+ OrderDetail orderDetail = Model1Factory.eINSTANCE.createOrderDetail();
+ add(order.getOrderDetails(), orderDetail);
+ }
+ }
+
+ for (int i = 0; i < 1000; i++)
+ {
+ SalesOrder order = Model1Factory.eINSTANCE.createSalesOrder();
+ order.setCustomer(company.getCustomers().get(i));
+ add(company.getSalesOrders(), order);
+
+ for (int j = 0; j < 100; j++)
+ {
+ OrderDetail orderDetail = Model1Factory.eINSTANCE.createOrderDetail();
+ add(order.getOrderDetails(), orderDetail);
+ }
+ }
+ }
+
+ private static void fillCategory(Category category, int depth)
+ {
+ for (int i = 0; i < 5; i++)
+ {
+ Category child = Model1Factory.eINSTANCE.createCategory();
+ add(category.getCategories(), child);
+ if (depth > 1)
+ {
+ fillCategory(child, depth - 1);
+ }
+ }
+
+ for (int i = 0; i < 20; i++)
+ {
+ Product1 product = Model1Factory.eINSTANCE.createProduct1();
+ add(category.getProducts(), product);
+ }
+ }
+
+ private static <T extends EObject> void add(EList<T> list, T object)
+ {
+ if (ADD_UNIQUE)
+ {
+ ((InternalEList<T>)list).addUnique(object);
+ }
+ else
+ {
+ list.add(object);
+ }
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static final class PrefetchResource
+ {
+ public static void main(String[] args) throws Exception
+ {
+ CDOSession session = openSession();
+
+ try
+ {
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(RESOURCE_NAME);
+
+ start("Prefetch Resource");
+ resource.cdoPrefetch(CDORevision.DEPTH_INFINITE);
+ stop();
+
+ iterateResource(resource);
+ }
+ finally
+ {
+ session.close();
+ }
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static final class CreateUnit
+ {
+ public static void main(String[] args) throws Exception
+ {
+ CDOSession session = openSession();
+
+ try
+ {
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(RESOURCE_NAME);
+
+ start("Create Unit");
+ resource.cdoView().getUnitManager().createUnit(resource);
+ stop();
+
+ iterateResource(resource);
+ }
+ finally
+ {
+ session.close();
+ }
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static final class OpenUnit
+ {
+ public static void main(String[] args) throws Exception
+ {
+ CDOSession session = openSession();
+
+ try
+ {
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(RESOURCE_NAME);
+
+ start("Open Unit");
+ resource.cdoView().getUnitManager().openUnit(resource);
+ stop();
+
+ iterateResource(resource);
+ }
+ finally
+ {
+ session.close();
+ }
+ }
+ }
+
+ private static CDOSession openSession()
+ {
+ IConnector connector = TCPUtil.getConnector(IPluginContainer.INSTANCE, "localhost");
+
+ CDONet4jSessionConfiguration configuration = CDONet4jUtil.createNet4jSessionConfiguration();
+ configuration.setConnector(connector);
+ configuration.setRepositoryName("repo1");
+ return configuration.openNet4jSession();
+ }
+
+ private static void iterateResource(CDOResource resource)
+ {
+ start("Iterate");
+ for (Iterator<EObject> it = resource.eAllContents(); it.hasNext();)
+ {
+ it.next();
+ }
+
+ stop();
+ }
+
+ private static void start(String msg)
+ {
+ start = System.currentTimeMillis();
+ System.out.print(msg + ": ");
+ }
+
+ private static void stop()
+ {
+ long stop = System.currentTimeMillis();
+ System.out.println(stop - start);
+ start = stop;
+ }
+
+ static
+ {
+ Model1Package.eINSTANCE.getClass();
+
+ Net4jUtil.prepareContainer(IPluginContainer.INSTANCE);
+ TCPUtil.prepareContainer(IPluginContainer.INSTANCE);
+ CDONet4jServerUtil.prepareContainer(IPluginContainer.INSTANCE);
+ CDONet4jUtil.prepareContainer(IPluginContainer.INSTANCE);
+ IPluginContainer.INSTANCE.activate();
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_329254_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_329254_Test.java
index 558d16f004..2fe86adfd0 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_329254_Test.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_329254_Test.java
@@ -31,6 +31,7 @@ import org.eclipse.net4j.util.io.IOUtil;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* LastCommitTimeStamp updated even when a serverSide Error occurred.
@@ -82,9 +83,10 @@ public class Bugzilla_329254_Test extends AbstractCDOTest
// grant the other session access to enter and
// block until it has left again.
enterLatch.countDown();
+
try
{
- leaveLatch.await();
+ leaveLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
}
catch (InterruptedException ex)
{
@@ -244,7 +246,7 @@ public class Bugzilla_329254_Test extends AbstractCDOTest
try
{
// wait until session 2 has entered write.
- enterLatch.await();
+ enterLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
}
catch (InterruptedException ex)
{
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_340709_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_340709_Test.java
index 98f48c2f1e..094c48b482 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_340709_Test.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_340709_Test.java
@@ -21,6 +21,7 @@ import org.eclipse.net4j.util.event.IEvent;
import org.eclipse.net4j.util.event.IListener;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* @author Martin Fluegge
@@ -70,7 +71,7 @@ public class Bugzilla_340709_Test extends AbstractCDOTest
try
{
- latch.await();
+ latch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
}
catch (InterruptedException ex)
{
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_349793_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_349793_Test.java
index d974bc46c7..3d2694de88 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_349793_Test.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_349793_Test.java
@@ -24,6 +24,7 @@ import org.eclipse.net4j.util.event.IEvent;
import org.eclipse.net4j.util.event.IListener;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* @author Egidijus Vaisnora
@@ -55,7 +56,7 @@ public class Bugzilla_349793_Test extends AbstractCDOTest
try
{
testExecutionLatch.countDown();
- invalidationLatch.await();
+ invalidationLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
}
catch (InterruptedException ex)
{
@@ -66,7 +67,7 @@ public class Bugzilla_349793_Test extends AbstractCDOTest
});
long timestamp = doSecondSessionSync();
- testExecutionLatch.await();
+ testExecutionLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
CDOTransaction freshTransaction = session.openTransaction();
invalidationLatch.countDown();
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_423699_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_423699_Test.java
index f2408663bf..4fd143d666 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_423699_Test.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_423699_Test.java
@@ -4,7 +4,7 @@
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
- *
+ *
* Contributors:
* Eike Stepper - initial API and implementation
*/
@@ -38,7 +38,6 @@ import java.util.LinkedHashSet;
*/
public class Bugzilla_423699_Test extends AbstractLockingTest
{
-
private CDOSession session;
private InternalCDOTransaction tx;
@@ -112,6 +111,7 @@ public class Bugzilla_423699_Test extends AbstractLockingTest
{
tx.enableDurableLocking();
}
+
CDOID containerID = container.cdoID();
CDOID childID = child.cdoID();
@@ -119,6 +119,7 @@ public class Bugzilla_423699_Test extends AbstractLockingTest
Collection<CDOObject> objectsToLock = new LinkedHashSet<CDOObject>();
objectsToLock.add(container);
objectsToLock.add(child);
+
tx.lockObjects(objectsToLock, LockType.WRITE, 10000);
assertIsLocked(durableLocking, true, containerID);
assertIsLocked(durableLocking, true, childID);
@@ -128,8 +129,10 @@ public class Bugzilla_423699_Test extends AbstractLockingTest
// Step 4: commit
tx.commit(new NullProgressMonitor());
+
// Lock should be deleted on detached object
assertIsLocked(durableLocking, false, childID);
+
// Lock should be deleted only if lock autorelease is enabled
assertIsLocked(durableLocking, !autoReleaseLocksEnabled, containerID);
@@ -142,6 +145,7 @@ public class Bugzilla_423699_Test extends AbstractLockingTest
session = openSession();
tx = (InternalCDOTransaction)session.openTransaction(durableLockingID);
tx.options().setAutoReleaseLocksEnabled(autoReleaseLocksEnabled);
+
// Lock states should not have changed
assertIsLocked(durableLocking, false, childID);
assertIsLocked(durableLocking, !autoReleaseLocksEnabled, containerID);
@@ -165,6 +169,7 @@ public class Bugzilla_423699_Test extends AbstractLockingTest
if (durably)
{
LockGrade durableLock = null;
+
try
{
InternalSession session = getRepository().getSessionManager().getSession(tx.getSessionID());
@@ -177,12 +182,14 @@ public class Bugzilla_423699_Test extends AbstractLockingTest
{
StoreThreadLocal.release();
}
+
assertEquals(elementID + " has not the expected durable lock status", shouldBeLocked, durableLock != null);
}
// Step 2: check lock
ArrayList<CDOID> elementIDs = new ArrayList<CDOID>();
elementIDs.add(elementID);
+
CDOLockState cdoLockState = tx.getLockStates(elementIDs)[0];
assertEquals(elementID + " has wrong lock status", shouldBeLocked, cdoLockState.getWriteLockOwner() != null);
}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_427773_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_427773_Test.java
index 33ca285381..1408bb950d 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_427773_Test.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_427773_Test.java
@@ -32,8 +32,6 @@ public class Bugzilla_427773_Test extends AbstractCDOTest
@Override
public void setUp() throws Exception
{
- SUPPRESS_OUTPUT = true;
-
UserManager userManager = new UserManager();
userManager.activate();
userManager.addUser(USER_1_CREDENTIALS.getUserID(), USER_1_CREDENTIALS.getPassword());
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485961_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485961_Test.java
index 7abbea6672..92c0c44cce 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485961_Test.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_485961_Test.java
@@ -54,13 +54,12 @@ public class Bugzilla_485961_Test extends AbstractCDOTest
InternalRepository repository = getRepository();
CDORevisionProvider revisionProvider = new ManagedRevisionProvider(repository.getRevisionManager(),
repository.getBranchManager().getMainBranch().getHead());
- CDOID rootResourceID = repository.getRootResourceID();
StoreThreadLocal.setSession(repository.getSessionManager().getSession(session.getSessionID()));
try
{
- assertEquals(8, traverse(revisionProvider, rootResourceID));
+ assertEquals(4, traverse(revisionProvider, res1.cdoID()));
}
finally
{
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458_Test.java
new file mode 100644
index 0000000000..015d974929
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458_Test.java
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.bugzilla;
+
+import org.eclipse.emf.cdo.CDOState;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.util.CDOException;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.server.IRepository.Props;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.spi.server.InternalSession;
+import org.eclipse.emf.cdo.spi.server.InternalView;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.config.IRepositoryConfig;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesBefore;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Skips;
+import org.eclipse.emf.cdo.tests.model1.Category;
+import org.eclipse.emf.cdo.tests.model1.Company;
+import org.eclipse.emf.cdo.tests.model1.Customer;
+import org.eclipse.emf.cdo.tests.model1.OrderDetail;
+import org.eclipse.emf.cdo.tests.model1.Product1;
+import org.eclipse.emf.cdo.tests.model1.PurchaseOrder;
+import org.eclipse.emf.cdo.tests.model1.SalesOrder;
+import org.eclipse.emf.cdo.tests.model1.Supplier;
+import org.eclipse.emf.cdo.tests.util.TestAdapter;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CDOUtil;
+import org.eclipse.emf.cdo.util.CommitException;
+import org.eclipse.emf.cdo.util.ConcurrentAccessException;
+import org.eclipse.emf.cdo.view.CDOAdapterPolicy;
+import org.eclipse.emf.cdo.view.CDOUnit;
+
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.InternalEList;
+import org.eclipse.emf.spi.cdo.InternalCDOView;
+
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Bug 486458 - Provide support for optimized loading and notifying of object units
+ *
+ * @author Eike Stepper
+ */
+@Requires({ IRepositoryConfig.CAPABILITY_AUDITING, "DB.ranges" })
+@Skips(IRepositoryConfig.CAPABILITY_BRANCHING)
+@CleanRepositoriesBefore(reason = "Instrumented repository")
+@CleanRepositoriesAfter(reason = "Instrumented repository")
+public class Bugzilla_486458_Test extends AbstractCDOTest
+{
+ @Override
+ protected void doSetUp() throws Exception
+ {
+ Map<String, Object> map = getTestProperties();
+ map.put(Props.SUPPORTING_UNITS, Boolean.toString(true));
+
+ super.doSetUp();
+ }
+
+ public void testPrefetchBigModel() throws Exception
+ {
+ fillRepository();
+ clearCache(getRepository().getRevisionManager());
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("test"));
+
+ long start = System.currentTimeMillis();
+ resource.cdoPrefetch(CDORevision.DEPTH_INFINITE);
+ long stop = System.currentTimeMillis();
+ System.out.println("Prefetched: " + (stop - start));
+
+ int count = iterateResource(resource);
+ assertEquals(7714, count);
+ }
+
+ public void testCreateUnit() throws Exception
+ {
+ fillRepository();
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("test"));
+
+ assertEquals(false, transaction.getUnitManager().isUnit(resource));
+ assertEquals(0, transaction.getUnitManager().getOpenUnits().length);
+
+ InternalSession serverSession = getRepository().getSessionManager().getSession(session.getSessionID());
+ InternalView serverView = serverSession.getView(transaction.getViewID());
+ CDOID childID = CDOUtil.getCDOObject(resource.getContents().get(0)).cdoID();
+ assertEquals(false, serverView.isInOpenUnit(childID));
+
+ long start = System.currentTimeMillis();
+ CDOUnit unit = transaction.getUnitManager().createUnit(resource);
+ long stop = System.currentTimeMillis();
+ System.out.println("Created Unit: " + (stop - start));
+
+ assertEquals(true, transaction.getUnitManager().isUnit(resource));
+ assertEquals(1, transaction.getUnitManager().getOpenUnits().length);
+ assertSame(unit, transaction.getUnitManager().getOpenUnits()[0]);
+ assertSame(unit, transaction.getUnitManager().getOpenUnit(resource));
+ assertEquals(true, serverView.isInOpenUnit(childID));
+
+ int count = iterateResource(resource);
+ assertEquals(7714, count);
+
+ unit.close();
+ assertEquals(true, transaction.getUnitManager().isUnit(resource));
+ assertEquals(0, transaction.getUnitManager().getOpenUnits().length);
+ assertEquals(null, transaction.getUnitManager().getOpenUnit(resource));
+ assertEquals(false, serverView.isInOpenUnit(childID));
+ }
+
+ public void testDetectNestedUnit() throws Exception
+ {
+ fillRepository();
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("test"));
+
+ CDOUnit unit = transaction.getUnitManager().createUnit(resource);
+ EObject parent = resource.getFolder();
+ EObject child = resource.getContents().get(0);
+
+ try
+ {
+ transaction.getUnitManager().createUnit(parent);
+ fail("CDOException expected");
+ }
+ catch (CDOException expected)
+ {
+ // SUCCESS
+ }
+
+ try
+ {
+ transaction.getUnitManager().createUnit(child);
+ fail("CDOException expected");
+ }
+ catch (CDOException expected)
+ {
+ // SUCCESS
+ }
+
+ assertEquals(true, transaction.getUnitManager().isUnit(resource));
+ assertEquals(false, transaction.getUnitManager().isUnit(parent));
+ assertEquals(false, transaction.getUnitManager().isUnit(child));
+
+ assertEquals(1, transaction.getUnitManager().getOpenUnits().length);
+ assertSame(unit, transaction.getUnitManager().getOpenUnits()[0]);
+ }
+
+ public void testOpenUnit() throws Exception
+ {
+ fillRepository();
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("test"));
+ CDOUnit createdUnit = transaction.getUnitManager().createUnit(resource);
+ assertEquals(7714, createdUnit.getElements());
+
+ session.close();
+ }
+
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("test"));
+
+ assertEquals(true, transaction.getUnitManager().isUnit(resource));
+ assertEquals(0, transaction.getUnitManager().getOpenUnits().length);
+
+ long start = System.currentTimeMillis();
+ CDOUnit openedUnit = transaction.getUnitManager().openUnit(resource);
+ assertEquals(7714, openedUnit.getElements());
+ long stop = System.currentTimeMillis();
+ System.out.println("Opened Unit: " + (stop - start));
+
+ assertEquals(true, transaction.getUnitManager().isUnit(resource));
+ assertEquals(1, transaction.getUnitManager().getOpenUnits().length);
+ assertSame(openedUnit, transaction.getUnitManager().getOpenUnits()[0]);
+
+ int count = iterateResource(resource);
+ assertEquals(7714, count);
+ }
+ }
+
+ public void testUpdateUnit() throws Exception
+ {
+ fillRepository();
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("test"));
+
+ CDOUnit unit = transaction.getUnitManager().createUnit(resource);
+ int elements = unit.getElements();
+
+ Company company = (Company)resource.getContents().get(0);
+ Category category = getModel1Factory().createCategory();
+ company.getCategories().add(category);
+ assertEquals(elements + 1, unit.getElements());
+
+ transaction.commit();
+ transaction.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.ALL);
+
+ category.eAdapters().add(new AdapterImpl());
+ assertEquals(false, ((InternalCDOView)transaction).hasSubscription(CDOUtil.getCDOObject(category).cdoID()));
+
+ company.getCategories().remove(category);
+ assertEquals(elements, unit.getElements());
+ }
+
+ public void testNotificationsAfterOpenUnit() throws Exception
+ {
+ fillRepository();
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ transaction.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.ALL);
+
+ CDOResource resource = transaction.getResource(getResourcePath("test"));
+ Company root = (Company)resource.getContents().get(0);
+ Category child = (Category)root.eContents().get(0);
+ Company sibling = (Company)resource.getContents().get(1);
+
+ CDOUnit unit = transaction.getUnitManager().createUnit(root);
+
+ TestAdapter adapter = new TestAdapter();
+ root.eAdapters().add(adapter);
+ child.eAdapters().add(adapter);
+ sibling.eAdapters().add(adapter);
+
+ assertEquals(false, ((InternalCDOView)transaction).hasSubscription(CDOUtil.getCDOObject(root).cdoID()));
+ assertEquals(false, ((InternalCDOView)transaction).hasSubscription(CDOUtil.getCDOObject(child).cdoID()));
+ assertEquals(true, ((InternalCDOView)transaction).hasSubscription(CDOUtil.getCDOObject(sibling).cdoID()));
+
+ InternalSession serverSession = getRepository().getSessionManager().getSession(session.getSessionID());
+ InternalView serverView = serverSession.getView(transaction.getViewID());
+ assertEquals(false, serverView.hasSubscription(CDOUtil.getCDOObject(root).cdoID()));
+ assertEquals(false, serverView.hasSubscription(CDOUtil.getCDOObject(child).cdoID()));
+ assertEquals(true, serverView.hasSubscription(CDOUtil.getCDOObject(sibling).cdoID()));
+
+ CDOSession session2 = openSession();
+ CDOTransaction transaction2 = session2.openTransaction();
+ CDOResource resource2 = transaction2.getResource(getResourcePath("test"));
+
+ Company root2 = (Company)resource2.getContents().get(0);
+ root2.setName("Name");
+ commitAndSync(transaction2, transaction);
+ assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(root).cdoState());
+ assertEquals("Name", root.getName());
+
+ Category child2 = (Category)root2.eContents().get(0);
+ child2.setName("Name");
+ commitAndSync(transaction2, transaction);
+ assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(child2).cdoState());
+ assertEquals("Name", child.getName());
+
+ Company sibling2 = (Company)resource2.getContents().get(1);
+ sibling2.setName("Name");
+ commitAndSync(transaction2, transaction);
+ assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(sibling2).cdoState());
+ assertEquals("Name", sibling.getName());
+
+ unit.close();
+
+ root2.setName("Name2");
+ commitAndSync(transaction2, transaction);
+ assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(root).cdoState());
+ assertEquals("Name2", root.getName());
+
+ child2.setName("Name2");
+ commitAndSync(transaction2, transaction);
+ assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(child2).cdoState());
+ assertEquals("Name2", child.getName());
+
+ sibling2.setName("Name2");
+ commitAndSync(transaction2, transaction);
+ assertEquals(CDOState.CLEAN, CDOUtil.getCDOObject(sibling2).cdoState());
+ assertEquals("Name2", sibling.getName());
+ }
+
+ private void fillRepository() throws ConcurrentAccessException, CommitException
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("test"));
+
+ for (int i = 0; i < 3; i++)
+ {
+ Company company = getModel1Factory().createCompany();
+ addUnique(resource.getContents(), company);
+ fillCompany(company);
+
+ long start = System.currentTimeMillis();
+ transaction.commit();
+ long stop = System.currentTimeMillis();
+ System.out.println("Committed: " + (stop - start));
+ }
+
+ session.close();
+ }
+
+ private void fillCompany(Company company)
+ {
+ for (int i = 0; i < 5; i++)
+ {
+ Category category = getModel1Factory().createCategory();
+ addUnique(company.getCategories(), category);
+ fillCategory(category, 3);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Supplier supplier = getModel1Factory().createSupplier();
+ addUnique(company.getSuppliers(), supplier);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Customer customer = getModel1Factory().createCustomer();
+ addUnique(company.getCustomers(), customer);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ PurchaseOrder order = getModel1Factory().createPurchaseOrder();
+ order.setSupplier(company.getSuppliers().get(i));
+ addUnique(company.getPurchaseOrders(), order);
+
+ for (int j = 0; j < 10; j++)
+ {
+ OrderDetail orderDetail = getModel1Factory().createOrderDetail();
+ addUnique(order.getOrderDetails(), orderDetail);
+ }
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ SalesOrder order = getModel1Factory().createSalesOrder();
+ order.setCustomer(company.getCustomers().get(i));
+ addUnique(company.getSalesOrders(), order);
+
+ for (int j = 0; j < 10; j++)
+ {
+ OrderDetail orderDetail = getModel1Factory().createOrderDetail();
+ addUnique(order.getOrderDetails(), orderDetail);
+ }
+ }
+ }
+
+ private void fillCategory(Category category, int depth)
+ {
+ for (int i = 0; i < 5; i++)
+ {
+ Category child = getModel1Factory().createCategory();
+ addUnique(category.getCategories(), child);
+ if (depth > 1)
+ {
+ fillCategory(child, depth - 1);
+ }
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Product1 product = getModel1Factory().createProduct1();
+ addUnique(category.getProducts(), product);
+ }
+ }
+
+ private static <T extends EObject> void addUnique(EList<T> list, T object)
+ {
+ ((InternalEList<T>)list).addUnique(object);
+ }
+
+ private static int iterateResource(CDOResource resource)
+ {
+ int count = 1;
+ long start = System.currentTimeMillis();
+
+ for (Iterator<EObject> it = resource.eAllContents(); it.hasNext();)
+ {
+ it.next();
+ ++count;
+ }
+
+ long stop = System.currentTimeMillis();
+ System.out.println("Iterated: " + (stop - start));
+
+ return count;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458a_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458a_Test.java
new file mode 100644
index 0000000000..a4c7b06814
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458a_Test.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.bugzilla;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.internal.server.Repository;
+import org.eclipse.emf.cdo.internal.server.TransactionCommitContext;
+import org.eclipse.emf.cdo.internal.server.UnitManager;
+import org.eclipse.emf.cdo.server.IRepository.Props;
+import org.eclipse.emf.cdo.server.IUnit;
+import org.eclipse.emf.cdo.server.IView;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.spi.server.InternalCommitContext;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
+import org.eclipse.emf.cdo.spi.server.InternalTransaction;
+import org.eclipse.emf.cdo.spi.server.InternalUnitManager;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.config.IRepositoryConfig;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesBefore;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Skips;
+import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig;
+import org.eclipse.emf.cdo.tests.model1.Category;
+import org.eclipse.emf.cdo.tests.model1.Company;
+import org.eclipse.emf.cdo.tests.model1.Customer;
+import org.eclipse.emf.cdo.tests.model1.OrderDetail;
+import org.eclipse.emf.cdo.tests.model1.Product1;
+import org.eclipse.emf.cdo.tests.model1.PurchaseOrder;
+import org.eclipse.emf.cdo.tests.model1.SalesOrder;
+import org.eclipse.emf.cdo.tests.model1.Supplier;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CommitException;
+import org.eclipse.emf.cdo.util.ConcurrentAccessException;
+
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.InternalEList;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Bug 486458 - Provide support for optimized loading and notifying of object units
+ * <p>
+ * Tests that a createUnit() that starts slightly before a commit() considers the newly attached objects.
+ *
+ * @author Eike Stepper
+ */
+@Requires({ IRepositoryConfig.CAPABILITY_AUDITING, "DB.ranges" })
+@Skips(IRepositoryConfig.CAPABILITY_BRANCHING)
+@CleanRepositoriesBefore(reason = "Instrumented repository")
+@CleanRepositoriesAfter(reason = "Instrumented repository")
+public class Bugzilla_486458a_Test extends AbstractCDOTest
+{
+ private CountDownLatch unitRegistered;
+
+ private CountDownLatch startInitializeUnit;
+
+ public void testCreateUnitWithParallelCommit() throws Exception
+ {
+ fillRepository();
+
+ unitRegistered = new CountDownLatch(1);
+ startInitializeUnit = new CountDownLatch(1);
+
+ final int[] committed = { 0 };
+
+ Thread committer = new Thread("Committer")
+ {
+ @Override
+ public void run()
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("test"));
+
+ Company company = (Company)resource.getContents().get(0);
+ Category category = company.getCategories().get(0);
+
+ committed[0] = fillCategory(category, 3);
+
+ try
+ {
+ unitRegistered.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException ex)
+ {
+ return;
+ }
+
+ try
+ {
+ transaction.commit();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ session.close();
+ }
+ };
+
+ committer.setDaemon(true);
+ committer.start();
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("test"));
+
+ transaction.getUnitManager().createUnit(resource);
+ committer.join(DEFAULT_TIMEOUT);
+
+ session = openSession();
+ transaction = session.openTransaction();
+ resource = transaction.getResource(getResourcePath("test"));
+
+ int count = iterateResource(resource);
+ int expected = 7714 + committed[0];
+ assertEquals(expected, count);
+
+ session = openSession();
+ transaction = session.openTransaction();
+ resource = transaction.getResource(getResourcePath("test"));
+
+ transaction.getUnitManager().openUnit(resource);
+
+ session = openSession();
+ transaction = session.openTransaction();
+ resource = transaction.getResource(getResourcePath("test"));
+
+ count = iterateResource(resource);
+ assertEquals(expected, count);
+ }
+
+ @Override
+ public synchronized Map<String, Object> getTestProperties()
+ {
+ Map<String, Object> map = super.getTestProperties();
+ map.put(Props.SUPPORTING_UNITS, Boolean.toString(true));
+ return map;
+ }
+
+ @Override
+ protected void doSetUp() throws Exception
+ {
+ createRepository();
+ super.doSetUp();
+ }
+
+ private void createRepository()
+ {
+ Repository repository = new Repository.Default()
+ {
+ @Override
+ public InternalCommitContext createCommitContext(InternalTransaction transaction)
+ {
+ return new TransactionCommitContext(transaction)
+ {
+ @Override
+ public void write(OMMonitor monitor)
+ {
+ if (startInitializeUnit != null)
+ {
+ startInitializeUnit.countDown();
+ }
+
+ super.write(monitor);
+ }
+ };
+ }
+
+ @Override
+ protected InternalUnitManager createUnitManager()
+ {
+ return new UnitManager(this)
+ {
+ @Override
+ protected UnitInitializer createUnitInitializer(CDOID rootID, IView view, CDORevisionHandler revisionHandler)
+ {
+ return new UnitInitializer(rootID, view, revisionHandler)
+ {
+ @Override
+ public IUnit initialize()
+ {
+ if (unitRegistered != null)
+ {
+ unitRegistered.countDown();
+ }
+
+ try
+ {
+ startInitializeUnit.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException ex)
+ {
+ return null;
+ }
+
+ return super.initialize();
+ }
+ };
+ }
+ };
+ }
+ };
+
+ Map<String, String> props = getRepositoryProperties();
+ ((InternalRepository)repository).setProperties(props);
+
+ repository.setName(IRepositoryConfig.REPOSITORY_NAME);
+
+ Map<String, Object> map = getTestProperties();
+ map.put(RepositoryConfig.PROP_TEST_REPOSITORY, repository);
+ }
+
+ private void fillRepository() throws ConcurrentAccessException, CommitException
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("test"));
+
+ for (int i = 0; i < 3; i++)
+ {
+ Company company = getModel1Factory().createCompany();
+ addUnique(resource.getContents(), company);
+ fillCompany(company);
+
+ long start = System.currentTimeMillis();
+ transaction.commit();
+ long stop = System.currentTimeMillis();
+ System.out.println("Committed: " + (stop - start));
+ }
+
+ session.close();
+ }
+
+ private void fillCompany(Company company)
+ {
+ for (int i = 0; i < 5; i++)
+ {
+ Category category = getModel1Factory().createCategory();
+ addUnique(company.getCategories(), category);
+ fillCategory(category, 3);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Supplier supplier = getModel1Factory().createSupplier();
+ addUnique(company.getSuppliers(), supplier);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Customer customer = getModel1Factory().createCustomer();
+ addUnique(company.getCustomers(), customer);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ PurchaseOrder order = getModel1Factory().createPurchaseOrder();
+ order.setSupplier(company.getSuppliers().get(i));
+ addUnique(company.getPurchaseOrders(), order);
+
+ for (int j = 0; j < 10; j++)
+ {
+ OrderDetail orderDetail = getModel1Factory().createOrderDetail();
+ addUnique(order.getOrderDetails(), orderDetail);
+ }
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ SalesOrder order = getModel1Factory().createSalesOrder();
+ order.setCustomer(company.getCustomers().get(i));
+ addUnique(company.getSalesOrders(), order);
+
+ for (int j = 0; j < 10; j++)
+ {
+ OrderDetail orderDetail = getModel1Factory().createOrderDetail();
+ addUnique(order.getOrderDetails(), orderDetail);
+ }
+ }
+ }
+
+ private int fillCategory(Category category, int depth)
+ {
+ int count = 0;
+
+ for (int i = 0; i < 5; i++)
+ {
+ Category child = getModel1Factory().createCategory();
+ addUnique(category.getCategories(), child);
+ ++count;
+
+ if (depth > 1)
+ {
+ count += fillCategory(child, depth - 1);
+ }
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Product1 product = getModel1Factory().createProduct1();
+ addUnique(category.getProducts(), product);
+ ++count;
+ }
+
+ return count;
+ }
+
+ private static <T extends EObject> void addUnique(EList<T> list, T object)
+ {
+ ((InternalEList<T>)list).addUnique(object);
+ }
+
+ private static int iterateResource(CDOResource resource)
+ {
+ int count = 1;
+ long start = System.currentTimeMillis();
+
+ for (Iterator<EObject> it = resource.eAllContents(); it.hasNext();)
+ {
+ it.next();
+ ++count;
+ }
+
+ long stop = System.currentTimeMillis();
+ System.out.println("Iterated: " + (stop - start));
+
+ return count;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458b_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458b_Test.java
new file mode 100644
index 0000000000..e6bfa290ed
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458b_Test.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.bugzilla;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.internal.server.Repository;
+import org.eclipse.emf.cdo.internal.server.UnitManager;
+import org.eclipse.emf.cdo.server.IRepository.Props;
+import org.eclipse.emf.cdo.server.IUnit;
+import org.eclipse.emf.cdo.server.IView;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
+import org.eclipse.emf.cdo.spi.server.InternalUnitManager;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.config.IRepositoryConfig;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesBefore;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Skips;
+import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig;
+import org.eclipse.emf.cdo.tests.model1.Category;
+import org.eclipse.emf.cdo.tests.model1.Company;
+import org.eclipse.emf.cdo.tests.model1.Customer;
+import org.eclipse.emf.cdo.tests.model1.OrderDetail;
+import org.eclipse.emf.cdo.tests.model1.Product1;
+import org.eclipse.emf.cdo.tests.model1.PurchaseOrder;
+import org.eclipse.emf.cdo.tests.model1.SalesOrder;
+import org.eclipse.emf.cdo.tests.model1.Supplier;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CommitException;
+import org.eclipse.emf.cdo.util.ConcurrentAccessException;
+import org.eclipse.emf.cdo.view.CDOUnit;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.InternalEList;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Bug 486458 - Provide support for optimized loading and notifying of object units
+ * <p>
+ * Tests that a commit() that starts slightly before a createUnit() contributes to the new unit.
+ *
+ * @author Eike Stepper
+ */
+@Requires({ IRepositoryConfig.CAPABILITY_AUDITING, "DB.ranges" })
+@Skips(IRepositoryConfig.CAPABILITY_BRANCHING)
+@CleanRepositoriesBefore(reason = "Instrumented repository")
+@CleanRepositoriesAfter(reason = "Instrumented repository")
+public class Bugzilla_486458b_Test extends AbstractCDOTest
+{
+ private CountDownLatch analyzeStarted;
+
+ private CountDownLatch initializeFinished;
+
+ private boolean longCommit;
+
+ public void testShortCommitWithParallelCreateUnit() throws Exception
+ {
+ fillRepository();
+
+ analyzeStarted = new CountDownLatch(1);
+
+ final int[] committed = { 0 };
+
+ Thread committer = new Thread("Committer")
+ {
+ @Override
+ public void run()
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("test"));
+
+ Company company = (Company)resource.getContents().get(0);
+ Category category = company.getCategories().get(0);
+
+ committed[0] = fillCategory(category, 3);
+
+ try
+ {
+ transaction.commit();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+
+ session.close();
+ }
+ };
+
+ committer.setDaemon(true);
+ committer.start();
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("test"));
+
+ transaction.getUnitManager().createUnit(resource);
+ committer.join(DEFAULT_TIMEOUT);
+
+ session = openSession();
+ transaction = session.openTransaction();
+ resource = transaction.getResource(getResourcePath("test"));
+
+ int count = iterateResource(resource);
+ int expected = 7714 + committed[0];
+ assertEquals(expected, count);
+
+ session = openSession();
+ transaction = session.openTransaction();
+ resource = transaction.getResource(getResourcePath("test"));
+
+ CDOUnit unit = transaction.getUnitManager().openUnit(resource);
+ assertEquals(expected, unit.getElements());
+
+ session = openSession();
+ transaction = session.openTransaction();
+ resource = transaction.getResource(getResourcePath("test"));
+
+ count = iterateResource(resource);
+ assertEquals(expected, count);
+ }
+
+ public void testLongCommitWithParallelCreateUnit() throws Exception
+ {
+ longCommit = true;
+ testShortCommitWithParallelCreateUnit();
+ }
+
+ @Override
+ public synchronized Map<String, Object> getTestProperties()
+ {
+ Map<String, Object> map = super.getTestProperties();
+ map.put(Props.SUPPORTING_UNITS, Boolean.toString(true));
+ return map;
+ }
+
+ @Override
+ protected void doSetUp() throws Exception
+ {
+ createRepository();
+ super.doSetUp();
+ }
+
+ private void createRepository()
+ {
+ Repository repository = new Repository.Default()
+ {
+ @Override
+ protected InternalUnitManager createUnitManager()
+ {
+ return new UnitManager(this)
+ {
+ @Override
+ protected void attachObjectsHook1()
+ {
+ try
+ {
+ Thread.sleep(2000);
+ }
+ catch (InterruptedException ex)
+ {
+ return;
+ }
+
+ if (analyzeStarted != null)
+ {
+ analyzeStarted.countDown();
+ }
+ }
+
+ @Override
+ public IUnit createUnit(CDOID rootID, IView view, CDORevisionHandler revisionHandler)
+ {
+ if (analyzeStarted != null)
+ {
+ try
+ {
+ analyzeStarted.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException ex)
+ {
+ return null;
+ }
+ }
+
+ return super.createUnit(rootID, view, revisionHandler);
+ }
+
+ @Override
+ protected UnitInitializer createUnitInitializer(CDOID rootID, IView view, CDORevisionHandler revisionHandler)
+ {
+ return new UnitInitializer(rootID, view, revisionHandler)
+ {
+ @Override
+ public IUnit initialize()
+ {
+ if (longCommit)
+ {
+ initializeFinished = new CountDownLatch(1);
+ }
+
+ try
+ {
+ return super.initialize();
+ }
+ finally
+ {
+ if (initializeFinished != null)
+ {
+ initializeFinished.countDown();
+ }
+ }
+ }
+ };
+ }
+
+ @Override
+ public void objectAttacherFinishedCommit(ObjectAttacher objectAttacher)
+ {
+ if (initializeFinished != null)
+ {
+ try
+ {
+ initializeFinished.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
+ Thread.sleep(2000);
+ }
+ catch (InterruptedException ex)
+ {
+ return;
+ }
+ }
+
+ super.objectAttacherFinishedCommit(objectAttacher);
+ }
+ };
+ }
+ };
+
+ Map<String, String> props = getRepositoryProperties();
+ ((InternalRepository)repository).setProperties(props);
+
+ repository.setName(IRepositoryConfig.REPOSITORY_NAME);
+
+ Map<String, Object> map = getTestProperties();
+ map.put(RepositoryConfig.PROP_TEST_REPOSITORY, repository);
+ }
+
+ private void fillRepository() throws ConcurrentAccessException, CommitException
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("test"));
+
+ for (int i = 0; i < 3; i++)
+ {
+ Company company = getModel1Factory().createCompany();
+ addUnique(resource.getContents(), company);
+ fillCompany(company);
+
+ long start = System.currentTimeMillis();
+ transaction.commit();
+ long stop = System.currentTimeMillis();
+ System.out.println("Committed: " + (stop - start));
+ }
+
+ session.close();
+ }
+
+ private void fillCompany(Company company)
+ {
+ for (int i = 0; i < 5; i++)
+ {
+ Category category = getModel1Factory().createCategory();
+ addUnique(company.getCategories(), category);
+ fillCategory(category, 3);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Supplier supplier = getModel1Factory().createSupplier();
+ addUnique(company.getSuppliers(), supplier);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Customer customer = getModel1Factory().createCustomer();
+ addUnique(company.getCustomers(), customer);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ PurchaseOrder order = getModel1Factory().createPurchaseOrder();
+ order.setSupplier(company.getSuppliers().get(i));
+ addUnique(company.getPurchaseOrders(), order);
+
+ for (int j = 0; j < 10; j++)
+ {
+ OrderDetail orderDetail = getModel1Factory().createOrderDetail();
+ addUnique(order.getOrderDetails(), orderDetail);
+ }
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ SalesOrder order = getModel1Factory().createSalesOrder();
+ order.setCustomer(company.getCustomers().get(i));
+ addUnique(company.getSalesOrders(), order);
+
+ for (int j = 0; j < 10; j++)
+ {
+ OrderDetail orderDetail = getModel1Factory().createOrderDetail();
+ addUnique(order.getOrderDetails(), orderDetail);
+ }
+ }
+ }
+
+ private int fillCategory(Category category, int depth)
+ {
+ int count = 0;
+
+ for (int i = 0; i < 5; i++)
+ {
+ Category child = getModel1Factory().createCategory();
+ addUnique(category.getCategories(), child);
+ ++count;
+
+ if (depth > 1)
+ {
+ count += fillCategory(child, depth - 1);
+ }
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Product1 product = getModel1Factory().createProduct1();
+ addUnique(category.getProducts(), product);
+ ++count;
+ }
+
+ return count;
+ }
+
+ private static <T extends EObject> void addUnique(EList<T> list, T object)
+ {
+ ((InternalEList<T>)list).addUnique(object);
+ }
+
+ private static int iterateResource(CDOResource resource)
+ {
+ int count = 1;
+ long start = System.currentTimeMillis();
+
+ for (Iterator<EObject> it = resource.eAllContents(); it.hasNext();)
+ {
+ it.next();
+ ++count;
+ }
+
+ long stop = System.currentTimeMillis();
+ System.out.println("Iterated: " + (stop - start));
+
+ return count;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458c_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458c_Test.java
new file mode 100644
index 0000000000..e37086b265
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_486458c_Test.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.bugzilla;
+
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.internal.server.Repository;
+import org.eclipse.emf.cdo.internal.server.UnitManager;
+import org.eclipse.emf.cdo.server.IRepository.Props;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.spi.server.InternalRepository;
+import org.eclipse.emf.cdo.spi.server.InternalUnitManager;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.config.IRepositoryConfig;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesBefore;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires;
+import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Skips;
+import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig;
+import org.eclipse.emf.cdo.tests.model1.Category;
+import org.eclipse.emf.cdo.tests.model1.Company;
+import org.eclipse.emf.cdo.tests.model1.Customer;
+import org.eclipse.emf.cdo.tests.model1.OrderDetail;
+import org.eclipse.emf.cdo.tests.model1.Product1;
+import org.eclipse.emf.cdo.tests.model1.PurchaseOrder;
+import org.eclipse.emf.cdo.tests.model1.SalesOrder;
+import org.eclipse.emf.cdo.tests.model1.Supplier;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CommitException;
+import org.eclipse.emf.cdo.util.ConcurrentAccessException;
+import org.eclipse.emf.cdo.view.CDOUnit;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.InternalEList;
+
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Bug 486458 - Provide support for optimized loading and notifying of object units
+ * <p>
+ * Tests that a createUnit() that starts slightly before another createUnit() creates/opens the same new unit.
+ *
+ * @author Eike Stepper
+ */
+@Requires({ IRepositoryConfig.CAPABILITY_AUDITING, "DB.ranges" })
+@Skips(IRepositoryConfig.CAPABILITY_BRANCHING)
+@CleanRepositoriesBefore(reason = "Instrumented repository")
+@CleanRepositoriesAfter(reason = "Instrumented repository")
+public class Bugzilla_486458c_Test extends AbstractCDOTest
+{
+ private CountDownLatch createStarted;
+
+ public void testParallelCreateUnits() throws Exception
+ {
+ fillRepository();
+
+ createStarted = new CountDownLatch(1);
+
+ final int[] secondCreated = { 0 };
+
+ Thread secondCreator = new Thread("Committer")
+ {
+ @Override
+ public void run()
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("test"));
+
+ try
+ {
+ createStarted.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException ex)
+ {
+ ex.printStackTrace();
+ return;
+ }
+
+ CDOUnit unit = transaction.getUnitManager().createUnit(resource);
+ secondCreated[0] = unit.getElements();
+
+ session.close();
+ }
+ };
+
+ secondCreator.setDaemon(true);
+ secondCreator.start();
+
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("test"));
+
+ CDOUnit unit = transaction.getUnitManager().createUnit(resource);
+ int created = unit.getElements();
+ assertEquals(7714, created);
+
+ secondCreator.join(DEFAULT_TIMEOUT);
+ assertEquals(7714, secondCreated[0]);
+ }
+
+ @Override
+ public synchronized Map<String, Object> getTestProperties()
+ {
+ Map<String, Object> map = super.getTestProperties();
+ map.put(Props.SUPPORTING_UNITS, Boolean.toString(true));
+ return map;
+ }
+
+ @Override
+ protected void doSetUp() throws Exception
+ {
+ createRepository();
+ super.doSetUp();
+ }
+
+ private void createRepository()
+ {
+ Repository repository = new Repository.Default()
+ {
+ @Override
+ protected InternalUnitManager createUnitManager()
+ {
+ return new UnitManager(this)
+ {
+ @Override
+ protected void createUnitHook1()
+ {
+ if (createStarted != null)
+ {
+ createStarted.countDown();
+ }
+ }
+ };
+ }
+ };
+
+ Map<String, String> props = getRepositoryProperties();
+ ((InternalRepository)repository).setProperties(props);
+
+ repository.setName(IRepositoryConfig.REPOSITORY_NAME);
+
+ Map<String, Object> map = getTestProperties();
+ map.put(RepositoryConfig.PROP_TEST_REPOSITORY, repository);
+ }
+
+ private void fillRepository() throws ConcurrentAccessException, CommitException
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("test"));
+
+ for (int i = 0; i < 3; i++)
+ {
+ Company company = getModel1Factory().createCompany();
+ addUnique(resource.getContents(), company);
+ fillCompany(company);
+
+ long start = System.currentTimeMillis();
+ transaction.commit();
+ long stop = System.currentTimeMillis();
+ System.out.println("Committed: " + (stop - start));
+ }
+
+ session.close();
+ }
+
+ private void fillCompany(Company company)
+ {
+ for (int i = 0; i < 5; i++)
+ {
+ Category category = getModel1Factory().createCategory();
+ addUnique(company.getCategories(), category);
+ fillCategory(category, 3);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Supplier supplier = getModel1Factory().createSupplier();
+ addUnique(company.getSuppliers(), supplier);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Customer customer = getModel1Factory().createCustomer();
+ addUnique(company.getCustomers(), customer);
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ PurchaseOrder order = getModel1Factory().createPurchaseOrder();
+ order.setSupplier(company.getSuppliers().get(i));
+ addUnique(company.getPurchaseOrders(), order);
+
+ for (int j = 0; j < 10; j++)
+ {
+ OrderDetail orderDetail = getModel1Factory().createOrderDetail();
+ addUnique(order.getOrderDetails(), orderDetail);
+ }
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ SalesOrder order = getModel1Factory().createSalesOrder();
+ order.setCustomer(company.getCustomers().get(i));
+ addUnique(company.getSalesOrders(), order);
+
+ for (int j = 0; j < 10; j++)
+ {
+ OrderDetail orderDetail = getModel1Factory().createOrderDetail();
+ addUnique(order.getOrderDetails(), orderDetail);
+ }
+ }
+ }
+
+ private int fillCategory(Category category, int depth)
+ {
+ int count = 0;
+
+ for (int i = 0; i < 5; i++)
+ {
+ Category child = getModel1Factory().createCategory();
+ addUnique(category.getCategories(), child);
+ ++count;
+
+ if (depth > 1)
+ {
+ count += fillCategory(child, depth - 1);
+ }
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ Product1 product = getModel1Factory().createProduct1();
+ addUnique(category.getProducts(), product);
+ ++count;
+ }
+
+ return count;
+ }
+
+ private static <T extends EObject> void addUnique(EList<T> list, T object)
+ {
+ ((InternalEList<T>)list).addUnique(object);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
index d0f55e331f..2d657e0222 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
@@ -51,6 +51,7 @@ import org.eclipse.emf.cdo.spi.server.InternalRepositorySynchronizer;
import org.eclipse.emf.cdo.spi.server.InternalSessionManager;
import org.eclipse.emf.cdo.spi.server.InternalStore;
import org.eclipse.emf.cdo.spi.server.InternalSynchronizableRepository;
+import org.eclipse.emf.cdo.spi.server.InternalUnitManager;
import org.eclipse.emf.cdo.tests.config.IRepositoryConfig;
import org.eclipse.emf.cdo.tests.config.IScenario;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.CleanRepositoriesAfter;
@@ -106,6 +107,8 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf
public static final String PROP_TEST_REVISION_MANAGER = "test.repository.RevisionManager";
+ public static final String PROP_TEST_UNIT_MANAGER = "test.repository.UnitManager";
+
public static final String PROP_TEST_SESSION_MANAGER = "test.repository.SessionManager";
public static final String PROP_TEST_AUTHENTICATOR = "test.repository.Authenticator";
@@ -604,6 +607,12 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf
repository.setRevisionManager(revisionManager);
+ InternalUnitManager unitManager = getTestUnitManager();
+ if (unitManager != null)
+ {
+ repository.setUnitManager(unitManager);
+ }
+
InternalSessionManager sessionManager = getTestSessionManager();
if (sessionManager == null)
{
@@ -652,6 +661,11 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf
return (InternalCDORevisionManager)getTestProperty(PROP_TEST_REVISION_MANAGER);
}
+ protected InternalUnitManager getTestUnitManager()
+ {
+ return (InternalUnitManager)getTestProperty(PROP_TEST_UNIT_MANAGER);
+ }
+
protected InternalSessionManager getTestSessionManager()
{
return (InternalSessionManager)getTestProperty(PROP_TEST_SESSION_MANAGER);
diff --git a/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/compare/CDOCompareEditorUtil.java b/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/compare/CDOCompareEditorUtil.java
index 672d70a51f..a2e6641fce 100644
--- a/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/compare/CDOCompareEditorUtil.java
+++ b/plugins/org.eclipse.emf.cdo.ui.compare/src/org/eclipse/emf/cdo/ui/compare/CDOCompareEditorUtil.java
@@ -15,6 +15,7 @@ import org.eclipse.emf.cdo.CDOState;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
import org.eclipse.emf.cdo.compare.CDOCompare;
import org.eclipse.emf.cdo.compare.CDOCompareUtil;
@@ -80,7 +81,6 @@ import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -814,7 +814,7 @@ public class CDOCompareEditorUtil
Collection<CDOObject> values = transaction.getNewObjects().values();
if (!values.isEmpty())
{
- Map<CDOID, CDOID> idMappings = new HashMap<CDOID, CDOID>();
+ Map<CDOID, CDOID> idMappings = CDOIDUtil.createMap();
CDOObject[] rightObjects = values.toArray(new CDOObject[values.size()]);
for (CDOObject rightObject : rightObjects)
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java
index 13ef778aaf..f139e2a2a7 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/transaction/CDOPushTransaction.java
@@ -32,6 +32,7 @@ import org.eclipse.emf.cdo.session.CDOSession;
import org.eclipse.emf.cdo.util.CommitException;
import org.eclipse.emf.cdo.view.CDOObjectHandler;
import org.eclipse.emf.cdo.view.CDOQuery;
+import org.eclipse.emf.cdo.view.CDOUnitManager;
import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.emf.cdo.view.CDOViewProvider;
import org.eclipse.emf.cdo.view.CDOViewSet;
@@ -954,6 +955,14 @@ public class CDOPushTransaction extends Notifier implements CDOTransaction
return delegate.getURIHandler();
}
+ /**
+ * @since 4.5
+ */
+ public CDOUnitManager getUnitManager()
+ {
+ return delegate.getUnitManager();
+ }
+
public String getCommitComment()
{
return delegate.getCommitComment();
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOUnit.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOUnit.java
new file mode 100644
index 0000000000..4411af376a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOUnit.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.view;
+
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @author Eike Stepper
+ * @since 4.5
+ */
+public interface CDOUnit
+{
+ public CDOUnitManager getManager();
+
+ public EObject getRoot();
+
+ public int getElements();
+
+ /**
+ * Same as calling {@link #close() close(true}.
+ */
+ public void close();
+
+ /**
+ * Closes this unit and optionally {@link CDOView.Options#addChangeSubscriptionPolicy(CDOAdapterPolicy) resubscribes}
+ * all contained objects for change notifications.
+ */
+ public void close(boolean resubscribe);
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOUnitManager.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOUnitManager.java
new file mode 100644
index 0000000000..fd94f255b7
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOUnitManager.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.view;
+
+import org.eclipse.emf.cdo.common.util.CDOException;
+
+import org.eclipse.net4j.util.container.IContainer;
+
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @author Eike Stepper
+ * @since 4.5
+ */
+public interface CDOUnitManager extends IContainer<CDOUnit>
+{
+ public CDOView getView();
+
+ public boolean isUnit(EObject root);
+
+ public CDOUnit createUnit(EObject root) throws UnitExistsException;
+
+ public CDOUnit openUnit(EObject root) throws UnitNotFoundException;
+
+ public CDOUnit getOpenUnit(EObject object);
+
+ public CDOUnit[] getOpenUnits();
+
+ /**
+ * @author Eike Stepper
+ */
+ public static final class UnitExistsException extends CDOException
+ {
+ private static final long serialVersionUID = 1L;
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public static final class UnitNotFoundException extends CDOException
+ {
+ private static final long serialVersionUID = 1L;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java
index 223ced6a12..23bba9b120 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/view/CDOView.java
@@ -155,6 +155,11 @@ public interface CDOView extends CDOCommonView, CDOUpdatable, CDOCommitHistory.P
public URIHandler getURIHandler();
/**
+ * @since 4.5
+ */
+ public CDOUnitManager getUnitManager();
+
+ /**
* Sets the {@link CDOBranch branch} and the point in (repository) time this view should refer to. {@link CDOObject
* Objects} provided by this view will be {@link CDORevision#isValid(long) valid} at this time. The special value
* {@link CDOCommonView#UNSPECIFIED_DATE UNSPECIFIED_DATE} denotes a "floating view" that always shows the latest
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java
index d616a5ad11..7ce0726286 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java
@@ -1061,6 +1061,22 @@ public class DelegatingSessionProtocol extends Lifecycle implements CDOSessionPr
}
}
+ public boolean requestUnit(int viewID, CDOID rootID, byte opcode, CDORevisionHandler revisionHandler)
+ {
+ int attempt = 0;
+ for (;;)
+ {
+ try
+ {
+ return delegate.requestUnit(viewID, rootID, opcode, revisionHandler);
+ }
+ catch (Exception ex)
+ {
+ handleException(++attempt, ex);
+ }
+ }
+ }
+
@Override
protected void doActivate() throws Exception
{
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java
index 925ae9391f..a2616b7ed1 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java
@@ -1993,6 +1993,8 @@ public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransa
// here be removed from the collection of reattached objects
lastSavepoint.getReattachedObjects().remove(id);
}
+
+ getUnitManager().removeObject(object);
}
finally
{
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java
index d5772c8206..37b00d69bd 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/AbstractCDOView.java
@@ -1777,7 +1777,13 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb
lastLookupObject = null;
}
- return objects.remove(id);
+ InternalCDOObject object = objects.remove(id);
+ if (object != null)
+ {
+ objectDeregistered(object);
+ }
+
+ return object;
}
finally
{
@@ -1786,6 +1792,11 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb
}
}
+ protected void objectDeregistered(InternalCDOObject object)
+ {
+ // Subclasses may override.
+ }
+
/**
* @return Never <code>null</code>
*/
@@ -2247,6 +2258,8 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb
TRACER.format(Messages.getString("CDOViewImpl.20"), old); //$NON-NLS-1$
}
}
+
+ objectRegistered(object);
}
finally
{
@@ -2255,6 +2268,11 @@ public abstract class AbstractCDOView extends CDOCommitHistoryProviderImpl<CDOOb
}
}
+ protected void objectRegistered(InternalCDOObject object)
+ {
+ // Subclasses may override.
+ }
+
public void deregisterObject(InternalCDOObject object)
{
synchronized (getViewMonitor())
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java
index 71f3f4ed2b..4087ffe837 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOViewImpl.java
@@ -25,9 +25,11 @@ import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation;
import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.lock.CDOLockUtil;
+import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch;
import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
import org.eclipse.emf.cdo.common.revision.CDORevisionManager;
import org.eclipse.emf.cdo.common.revision.CDORevisionsLoadedEvent;
@@ -51,6 +53,8 @@ import org.eclipse.emf.cdo.view.CDOFeatureAnalyzer;
import org.eclipse.emf.cdo.view.CDOInvalidationPolicy;
import org.eclipse.emf.cdo.view.CDORevisionPrefetchingPolicy;
import org.eclipse.emf.cdo.view.CDOStaleReferencePolicy;
+import org.eclipse.emf.cdo.view.CDOUnit;
+import org.eclipse.emf.cdo.view.CDOUnitManager;
import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.emf.cdo.view.CDOViewDurabilityChangedEvent;
import org.eclipse.emf.cdo.view.CDOViewInvalidationEvent;
@@ -74,6 +78,7 @@ import org.eclipse.net4j.util.concurrent.IExecutorServiceProvider;
import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
import org.eclipse.net4j.util.concurrent.IWorkSerializer;
import org.eclipse.net4j.util.concurrent.RunnableWithName;
+import org.eclipse.net4j.util.container.Container;
import org.eclipse.net4j.util.event.IEvent;
import org.eclipse.net4j.util.event.IListener;
import org.eclipse.net4j.util.event.Notifier;
@@ -95,6 +100,7 @@ import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.spi.cdo.CDOSessionProtocol;
import org.eclipse.emf.spi.cdo.CDOSessionProtocol.LockObjectsResult;
import org.eclipse.emf.spi.cdo.CDOSessionProtocol.UnlockObjectsResult;
@@ -113,9 +119,11 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.CountDownLatch;
@@ -135,6 +143,8 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv
private String durableLockingID;
+ private final CDOUnitManagerImpl unitManager = new CDOUnitManagerImpl();
+
private ChangeSubscriptionManager changeSubscriptionManager = new ChangeSubscriptionManager();
private AdapterManager adapterManager = new AdapterManager();
@@ -926,23 +936,15 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv
}
@Override
- public InternalCDOObject removeObject(CDOID id)
+ protected void objectRegistered(InternalCDOObject object)
{
- synchronized (getViewMonitor())
- {
- lockView();
+ unitManager.addObject(object);
+ }
- try
- {
- InternalCDOObject removedObject = super.removeObject(id);
- removeLockState(removedObject);
- return removedObject;
- }
- finally
- {
- unlockView();
- }
- }
+ @Override
+ protected void objectDeregistered(InternalCDOObject object)
+ {
+ removeLockState(object);
}
public CDOLockState[] getLockStates(Collection<CDOID> ids)
@@ -1551,6 +1553,8 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv
{
new SyncTester().start();
}
+
+ unitManager.activate();
}
@Override
@@ -1591,6 +1595,8 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv
@Override
protected void doDeactivate() throws Exception
{
+ unitManager.deactivate();
+
CDOViewRegistryImpl.INSTANCE.deregister(this);
LifecycleUtil.deactivate(invalidationRunner, OMLogger.Level.WARN);
@@ -1805,6 +1811,346 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv
return id;
}
+ public final CDOUnitManagerImpl getUnitManager()
+ {
+ return unitManager;
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public final class CDOUnitManagerImpl extends Container<CDOUnit> implements CDOUnitManager
+ {
+ private final Map<EObject, CDOUnit> unitPerRoot = new HashMap<EObject, CDOUnit>();
+
+ private final Map<EObject, CDOUnit> unitPerObject = new HashMap<EObject, CDOUnit>();
+
+ public CDOUnitManagerImpl()
+ {
+ }
+
+ public CDOView getView()
+ {
+ return CDOViewImpl.this;
+ }
+
+ public boolean isUnit(EObject root)
+ {
+ CDOUnitImpl unit = requestUnit(root, CDOProtocolConstants.UNIT_CHECK);
+ return unit != null;
+ }
+
+ public CDOUnit createUnit(EObject root) throws UnitExistsException
+ {
+ CDOUnitImpl unit = requestUnit(root, CDOProtocolConstants.UNIT_CREATE);
+ if (unit == null)
+ {
+ throw new UnitExistsException();
+ }
+
+ fireElementAddedEvent(unit);
+ return unit;
+ }
+
+ public CDOUnit openUnit(EObject root) throws UnitNotFoundException
+ {
+ CDOUnitImpl unit = requestUnit(root, CDOProtocolConstants.UNIT_OPEN);
+ if (unit == null)
+ {
+ throw new UnitNotFoundException();
+ }
+
+ fireElementAddedEvent(unit);
+ return unit;
+ }
+
+ public CDOUnit[] getElements()
+ {
+ synchronized (getViewMonitor())
+ {
+ lockView();
+
+ try
+ {
+ return unitPerRoot.values().toArray(new CDOUnit[unitPerRoot.size()]);
+ }
+ finally
+ {
+ unlockView();
+ }
+ }
+ }
+
+ public CDOUnit[] getOpenUnits()
+ {
+ return getElements();
+ }
+
+ public CDOUnit getOpenUnit(EObject object)
+ {
+ synchronized (getViewMonitor())
+ {
+ lockView();
+
+ try
+ {
+ return getOpenUnitUnsynced(object);
+ }
+ finally
+ {
+ unlockView();
+ }
+ }
+ }
+
+ public CDOUnit getOpenUnitUnsynced(EObject object)
+ {
+ return unitPerObject.get(object);
+ }
+
+ public void addObject(InternalCDOObject object)
+ {
+ if (!unitPerRoot.isEmpty())
+ {
+ CDOUnit unit = getOpenUnitUnsynced(object);
+ if (unit == null)
+ {
+ EObject parent = getParent(object);
+ EObject rootResource = getRootResource();
+
+ while (parent != null && parent != rootResource)
+ {
+ unit = getOpenUnitUnsynced(parent);
+ if (unit != null)
+ {
+ unitPerObject.put(object, unit);
+ ++((CDOUnitImpl)unit).elements;
+ break;
+ }
+
+ parent = getParent(parent);
+ }
+ }
+ }
+ }
+
+ public void removeObject(InternalCDOObject object)
+ {
+ if (!unitPerRoot.isEmpty())
+ {
+ CDOUnit unit = unitPerObject.remove(object);
+ if (unit != null)
+ {
+ if (unit.getRoot() == object)
+ {
+ unitPerRoot.remove(object);
+ }
+
+ --((CDOUnitImpl)unit).elements;
+ }
+ }
+ }
+
+ @Override
+ protected void doDeactivate() throws Exception
+ {
+ unitPerRoot.clear();
+ unitPerObject.clear();
+ super.doDeactivate();
+ }
+
+ private EObject getParent(EObject object)
+ {
+ EObject parent = object.eContainer();
+ if (parent == null)
+ {
+ parent = (EObject)((InternalEObject)object).eDirectResource();
+ }
+
+ return parent;
+ }
+
+ private CDOObject getCDORoot(EObject root)
+ {
+ CDOObject cdoRoot = CDOUtil.getCDOObject(root);
+ if (cdoRoot == null)
+ {
+ throw new IllegalArgumentException("Root " + root + " is not managed by CDO");
+ }
+
+ CDOView view = cdoRoot.cdoView();
+ if (view != CDOViewImpl.this)
+ {
+ throw new IllegalArgumentException("Root " + root + " is managed by " + view);
+ }
+
+ return cdoRoot;
+ }
+
+ private CDOUnitImpl requestUnit(EObject root, byte opcode)
+ {
+ synchronized (getViewMonitor())
+ {
+ lockView();
+
+ try
+ {
+ if (opcode == CDOProtocolConstants.UNIT_CREATE)
+ {
+ CDOUnit containingUnit = getOpenUnit(root);
+ if (containingUnit != null)
+ {
+ throw new CDOException(
+ "Attempt to nest the new unit " + root + " in the existing unit " + containingUnit);
+ }
+
+ for (CDOUnit existingUnit : unitPerRoot.values())
+ {
+ if (EcoreUtil.isAncestor(root, existingUnit.getRoot()))
+ {
+ throw new CDOException(
+ "Attempt to nest the existing unit " + existingUnit + " in the new unit " + root);
+ }
+ }
+ }
+
+ final InternalCDORevisionManager revisionManager = session.getRevisionManager();
+ final CDOUnitImpl unit = new CDOUnitImpl(root);
+
+ int viewID = getViewID();
+ CDOID rootID = getCDORoot(root).cdoID();
+
+ CDORevisionHandler revisionHandler = opcode == CDOProtocolConstants.UNIT_CREATE
+ || opcode == CDOProtocolConstants.UNIT_OPEN ? new CDORevisionHandler()
+ {
+ public boolean handleRevision(CDORevision revision)
+ {
+ ++unit.elements;
+ revisionManager.addRevision(revision);
+
+ CDOID id = revision.getID();
+ changeSubscriptionManager.removeEntry(id);
+
+ InternalCDOObject object = getObject(id);
+ unitPerObject.put(object, unit);
+ return true;
+ }
+ } : null;
+
+ CDOSessionProtocol sessionProtocol = session.getSessionProtocol();
+ boolean success = sessionProtocol.requestUnit(viewID, rootID, opcode, revisionHandler);
+
+ if (success)
+ {
+ if (revisionHandler != null)
+ {
+ unitPerRoot.put(root, unit);
+ unitPerObject.put(root, unit);
+ }
+
+ return unit;
+ }
+
+ return null;
+ }
+ finally
+ {
+ unlockView();
+ }
+ }
+ }
+
+ private void closeUnit(CDOUnit unit, boolean resubscribe)
+ {
+ synchronized (getViewMonitor())
+ {
+ lockView();
+
+ try
+ {
+ requestUnit(unit.getRoot(), CDOProtocolConstants.UNIT_CLOSE);
+
+ if (resubscribe && !options.hasChangeSubscriptionPolicies())
+ {
+ resubscribe = false;
+ }
+
+ for (Iterator<Entry<EObject, CDOUnit>> it = unitPerObject.entrySet().iterator(); it.hasNext();)
+ {
+ Entry<EObject, CDOUnit> entry = it.next();
+ if (entry.getValue() == unit)
+ {
+ it.remove(); // Remove the object from its unit first, so that shouldSubscribe() can return true.
+
+ if (resubscribe)
+ {
+ EObject object = entry.getKey();
+ for (Adapter adapter : object.eAdapters())
+ {
+ changeSubscriptionManager.subscribe(object, adapter);
+ }
+ }
+ }
+ }
+
+ unitPerRoot.remove(unit.getRoot());
+ }
+ finally
+ {
+ unlockView();
+ }
+ }
+
+ fireElementRemovedEvent(unit);
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ public final class CDOUnitImpl implements CDOUnit
+ {
+ private final EObject root;
+
+ private int elements;
+
+ public CDOUnitImpl(EObject root)
+ {
+ this.root = root;
+ }
+
+ public CDOUnitManagerImpl getManager()
+ {
+ return CDOUnitManagerImpl.this;
+ }
+
+ public EObject getRoot()
+ {
+ return root;
+ }
+
+ public int getElements()
+ {
+ return elements;
+ }
+
+ public void close()
+ {
+ close(true);
+ }
+
+ public void close(boolean resubscribe)
+ {
+ closeUnit(this, resubscribe);
+ }
+
+ @Override
+ public String toString()
+ {
+ return "CDOUnit[" + root + "]";
+ }
+ }
+ }
+
/**
* @author Simon McDuff
* @since 2.0
@@ -1926,7 +2272,7 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv
/**
* Register to the server all objects from the active list
*/
- private void notifyChangeSubcriptionPolicy()
+ private void handleChangeSubcriptionPoliciesChanged()
{
boolean policiesPresent = options().hasChangeSubscriptionPolicies();
subscriptions.clear();
@@ -1964,13 +2310,13 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv
{
for (CDOObject object : newObjects)
{
- InternalCDOObject cdoDetachedObject = (InternalCDOObject)object;
- if (cdoDetachedObject != null)
+ InternalCDOObject internalObject = (InternalCDOObject)object;
+ if (internalObject != null)
{
- int count = getNumberOfValidAdapters(cdoDetachedObject);
+ int count = getNumberOfValidAdapters(internalObject);
if (count > 0)
{
- subscribe(cdoDetachedObject.cdoID(), cdoDetachedObject, count);
+ subscribe(internalObject.cdoID(), internalObject, count);
}
}
}
@@ -2031,6 +2377,11 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv
private boolean shouldSubscribe(EObject eObject, Adapter adapter)
{
+ if (unitManager.getOpenUnitUnsynced(eObject) != null)
+ {
+ return false;
+ }
+
for (CDOAdapterPolicy policy : options().getChangeSubscriptionPolicies())
{
if (policy.isValid(eObject, adapter))
@@ -2072,7 +2423,7 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv
// Look if objects need to be unsubscribe
if (count <= 0)
{
- subscriptions.remove(id);
+ removeEntry(id);
// Notification need to be enable to send correct value to the server
if (policiesPresent)
@@ -2098,9 +2449,14 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv
subscribe(id, null, Integer.MIN_VALUE);
}
- private void addEntry(CDOID key, InternalCDOObject object, int count)
+ private void addEntry(CDOID id, InternalCDOObject object, int count)
+ {
+ subscriptions.put(id, new SubscribeEntry(object, count));
+ }
+
+ private void removeEntry(CDOID id)
{
- subscriptions.put(key, new SubscribeEntry(object, count));
+ subscriptions.remove(id);
}
}
@@ -2136,7 +2492,8 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv
}
/**
- * A {@link IListener} to prefetch {@link CDOLockState lockstates} when {@link CDORevision revisions} are loaded, according to {@link Options#setLockStatePrefetchEnabled(boolean)} option.
+ * A {@link IListener} to prefetch {@link CDOLockState lock states} when {@link CDORevision revisions} are loaded,
+ * according to {@link Options#setLockStatePrefetchEnabled(boolean)} option.
*
* @author Esteban Dugueperoux
*/
@@ -2814,7 +3171,7 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv
{
if (changeSubscriptionPolicies.add(policy))
{
- changeSubscriptionManager.notifyChangeSubcriptionPolicy();
+ changeSubscriptionManager.handleChangeSubcriptionPoliciesChanged();
event = new ChangeSubscriptionPoliciesEventImpl();
}
}
@@ -2840,7 +3197,7 @@ public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProv
{
if (changeSubscriptionPolicies.remove(policy) && !changeSubscriptionPolicies.contains(policy))
{
- changeSubscriptionManager.notifyChangeSubcriptionPolicy();
+ changeSubscriptionManager.handleChangeSubcriptionPoliciesChanged();
event = new ChangeSubscriptionPoliciesEventImpl();
}
}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOMergingConflictResolver.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOMergingConflictResolver.java
index 59020e5dc5..847a3bbf51 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOMergingConflictResolver.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOMergingConflictResolver.java
@@ -45,7 +45,6 @@ import org.eclipse.net4j.util.om.trace.ContextTracer;
import org.eclipse.emf.ecore.EStructuralFeature;
-import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@@ -402,7 +401,7 @@ public class CDOMergingConflictResolver extends AbstractChangeSetsConflictResolv
public ObjectsMapUpdater(Map<CDOID, CDOObject> map)
{
- mapCopy = new HashMap<CDOID, CDOObject>(map);
+ mapCopy = CDOIDUtil.createMap(map);
map.clear();
this.map = map;
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java
index ec58ab8fcd..1b7fe9ab91 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java
@@ -35,6 +35,7 @@ import org.eclipse.emf.cdo.common.protocol.CDODataInput;
import org.eclipse.emf.cdo.common.protocol.CDOProtocol;
import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
import org.eclipse.emf.cdo.common.security.CDOPermission;
import org.eclipse.emf.cdo.common.util.CDOCommonUtil;
@@ -343,6 +344,11 @@ public interface CDOSessionProtocol extends CDOProtocol, PackageLoader, BranchLo
public void requestResetCredentials(String userID);
/**
+ * @since 4.5
+ */
+ public boolean requestUnit(int viewID, CDOID rootID, byte opcode, CDORevisionHandler revisionHandler);
+
+ /**
* If the meaning of this type isn't clear, there really should be more of a description here...
*
* @author Eike Stepper
diff --git a/plugins/org.eclipse.net4j.db.h2/H2 Browser.launch b/plugins/org.eclipse.net4j.db.h2/H2 Browser.launch
new file mode 100644
index 0000000000..acf966ae38
--- /dev/null
+++ b/plugins/org.eclipse.net4j.db.h2/H2 Browser.launch
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/org.eclipse.net4j.db.h2"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="4"/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.h2.tools.Server"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.net4j.db.h2"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms1G&#13;&#10;-Xmx1G"/>
+</launchConfiguration>
diff --git a/plugins/org.eclipse.net4j.db.mysql/META-INF/MANIFEST.MF b/plugins/org.eclipse.net4j.db.mysql/META-INF/MANIFEST.MF
index 282416a59f..bb9bcb9331 100644
--- a/plugins/org.eclipse.net4j.db.mysql/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.net4j.db.mysql/META-INF/MANIFEST.MF
@@ -1,7 +1,7 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.eclipse.net4j.db.mysql;singleton:=true
-Bundle-Version: 4.2.200.qualifier
+Bundle-Version: 4.2.300.qualifier
Bundle-Name: %pluginName
Bundle-Vendor: %providerName
Bundle-Localization: plugin
@@ -13,6 +13,6 @@ Require-Bundle: org.eclipse.net4j.db;bundle-version="[4.0.0,5.0.0)";visibility:=
Import-Package: com.mysql.jdbc;version="[5.0.0,6.0.0)";resolution:=optional;x-installation:=greedy,
com.mysql.jdbc.jdbc2.optional;version="[5.0.0,6.0.0)";resolution:=optional;x-installation:=greedy,
org.osgi.framework;version="[1.0.0,2.0.0)"
-Export-Package: org.eclipse.net4j.db.internal.mysql.bundle;version="4.2.200";x-internal:=true,
- org.eclipse.net4j.db.mysql;version="4.2.200"
+Export-Package: org.eclipse.net4j.db.internal.mysql.bundle;version="4.2.300";x-internal:=true,
+ org.eclipse.net4j.db.mysql;version="4.2.300"
Eclipse-RegisterBuddy: org.eclipse.net4j.db
diff --git a/plugins/org.eclipse.net4j.db.mysql/src/org/eclipse/net4j/db/mysql/MYSQLAdapter.java b/plugins/org.eclipse.net4j.db.mysql/src/org/eclipse/net4j/db/mysql/MYSQLAdapter.java
index 87469593c4..87f9d0cf15 100644
--- a/plugins/org.eclipse.net4j.db.mysql/src/org/eclipse/net4j/db/mysql/MYSQLAdapter.java
+++ b/plugins/org.eclipse.net4j.db.mysql/src/org/eclipse/net4j/db/mysql/MYSQLAdapter.java
@@ -16,6 +16,9 @@ import org.eclipse.net4j.db.ddl.IDBField;
import org.eclipse.net4j.db.ddl.IDBIndex;
import org.eclipse.net4j.spi.db.DBAdapter;
+import com.mysql.jdbc.ConnectionProperties;
+
+import java.sql.Connection;
import java.sql.SQLException;
/**
@@ -32,39 +35,39 @@ public class MYSQLAdapter extends DBAdapter
private static final String[] RESERVED_WORDS = { "ACCESSIBLE", "ACTION", "ADD", "ALL", "ALTER", "ANALYZE", "AND", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
"AS", //$NON-NLS-1$
- "ASC", "ASENSITIVE", "BEFORE", "BETWEEN", "BIGINT", "BINARY", "BIT", "BLOB", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "BOTH", "BY", "CALL", "CASCADE", "CASE", "CHANGE", "CHAR", "CHARACTER", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "CHECK", "COLLATE", "COLUMN", "COLUMNS", "CONDITION", "CONNECTION", "CONSTRAINT", "CONTINUE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "CONVERT", "CREATE", "CROSS", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "DATABASE", "DATABASES", "DATE", "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", "DAY_SECOND", "DEC", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "DECIMAL", "DECLARE", "DEFAULT", "DELAYED", "DELETE", "DESC", "DESCRIBE", "DETERMINISTIC", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "DISTINCT", "DISTINCTROW", "DIV", "DOUBLE", "DROP", "DUAL", "EACH", "ELSE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "ELSEIF", "ENCLOSED", "ENUM", "ESCAPED", "EXISTS", "EXIT", "EXPLAIN", "FALSE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "FETCH", "FIELDS", "FLOAT", "FLOAT4", "FLOAT8", "FOR", "FORCE", "FOREIGN", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "FROM", "FULLTEXT", "GENERAL", "GOTO", "GRANT", "GROUP", "HAVING", "HIGH_PRIORITY", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "HOUR_MICROSECOND", "HOUR_MINUTE", "HOUR_SECOND", "IF", "IGNORE", "IGNORE_SERVER_IDS", "IN", "INDEX", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "INFILE", "INNER", "INOUT", "INSENSITIVE", "INSERT", "INT", "INT1", "INT2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "INT3", "INT4", "INT8", "INTEGER", "INTERVAL", "INTO", "IS", "ITERATE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "JOIN", "KEY", "KEYS", "KILL", "LABEL", "LEADING", "LEAVE", "LEFT", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "LIKE", "LIMIT", "LINEAR", "LINES", "LOAD", "LOCALTIME", "LOCALTIMESTAMP", "LOCK", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "LONG", "LONGBLOB", "LONGTEXT", "LOOP", "LOW_PRIORITY", "MASTER_HEARTBEAT_PERIOD", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
+ "ASC", "ASENSITIVE", "BEFORE", "BETWEEN", "BIGINT", "BINARY", "BIT", "BLOB", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "BOTH", "BY", "CALL", "CASCADE", "CASE", "CHANGE", "CHAR", "CHARACTER", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "CHECK", "COLLATE", "COLUMN", "COLUMNS", "CONDITION", "CONNECTION", "CONSTRAINT", "CONTINUE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "CONVERT", "CREATE", "CROSS", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "DATABASE", "DATABASES", "DATE", "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", "DAY_SECOND", "DEC", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "DECIMAL", "DECLARE", "DEFAULT", "DELAYED", "DELETE", "DESC", "DESCRIBE", "DETERMINISTIC", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "DISTINCT", "DISTINCTROW", "DIV", "DOUBLE", "DROP", "DUAL", "EACH", "ELSE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "ELSEIF", "ENCLOSED", "ENUM", "ESCAPED", "EXISTS", "EXIT", "EXPLAIN", "FALSE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "FETCH", "FIELDS", "FLOAT", "FLOAT4", "FLOAT8", "FOR", "FORCE", "FOREIGN", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "FROM", "FULLTEXT", "GENERAL", "GOTO", "GRANT", "GROUP", "HAVING", "HIGH_PRIORITY", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "HOUR_MICROSECOND", "HOUR_MINUTE", "HOUR_SECOND", "IF", "IGNORE", "IGNORE_SERVER_IDS", "IN", "INDEX", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "INFILE", "INNER", "INOUT", "INSENSITIVE", "INSERT", "INT", "INT1", "INT2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "INT3", "INT4", "INT8", "INTEGER", "INTERVAL", "INTO", "IS", "ITERATE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "JOIN", "KEY", "KEYS", "KILL", "LABEL", "LEADING", "LEAVE", "LEFT", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "LIKE", "LIMIT", "LINEAR", "LINES", "LOAD", "LOCALTIME", "LOCALTIMESTAMP", "LOCK", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "LONG", "LONGBLOB", "LONGTEXT", "LOOP", "LOW_PRIORITY", "MASTER_HEARTBEAT_PERIOD", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
"MASTER_SSL_VERIFY_SERVER_CERT", "MATCH", //$NON-NLS-1$ //$NON-NLS-2$
- "MAXVALUE", "MEDIUMBLOB", "MEDIUMINT", "MEDIUMTEXT", "MIDDLEINT", "MINUTE_MICROSECOND", "MINUTE_SECOND", "MOD", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "MODIFIES", "NATURAL", "NO", "NOT", "NO_WRITE_TO_BINLOG", "NULL", "NUMERIC", "ON", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "OPTIMIZE", "OPTION", "OPTIONALLY", "OR", "ORDER", "OUT", "OUTER", "OUTFILE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "PRECISION", "PRIMARY", "PRIVILEGES", "PROCEDURE", "PURGE", "RAID0", "RANGE", "READ", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "READS", "READ_WRITE", "REAL", "REFERENCES", "REGEXP", "RELEASE", "RENAME", "REPEAT", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "REPLACE", "REQUIRE", "RESIGNAL", "RESTRICT", "RETURN", "REVOKE", "RIGHT", "RLIKE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "SCHEMA", "SCHEMAS", "SECOND_MICROSECOND", "SELECT", "SENSITIVE", "SEPARATOR", "SET", "SHOW", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "SIGNAL", "SLOW", "SMALLINT", "SONAME", "SPATIAL", "SPECIFIC", "SQL", "SQL_BIG_RESULT", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "SQL_CALC_FOUND_ROWS", "SQLEXCEPTION", "SQL_SMALL_RESULT", "SQLSTATE", "SQLWARNING", "SSL", "STARTING", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
+ "MAXVALUE", "MEDIUMBLOB", "MEDIUMINT", "MEDIUMTEXT", "MIDDLEINT", "MINUTE_MICROSECOND", "MINUTE_SECOND", "MOD", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "MODIFIES", "NATURAL", "NO", "NOT", "NO_WRITE_TO_BINLOG", "NULL", "NUMERIC", "ON", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "OPTIMIZE", "OPTION", "OPTIONALLY", "OR", "ORDER", "OUT", "OUTER", "OUTFILE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "PRECISION", "PRIMARY", "PRIVILEGES", "PROCEDURE", "PURGE", "RAID0", "RANGE", "READ", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "READS", "READ_WRITE", "REAL", "REFERENCES", "REGEXP", "RELEASE", "RENAME", "REPEAT", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "REPLACE", "REQUIRE", "RESIGNAL", "RESTRICT", "RETURN", "REVOKE", "RIGHT", "RLIKE", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "SCHEMA", "SCHEMAS", "SECOND_MICROSECOND", "SELECT", "SENSITIVE", "SEPARATOR", "SET", "SHOW", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "SIGNAL", "SLOW", "SMALLINT", "SONAME", "SPATIAL", "SPECIFIC", "SQL", "SQL_BIG_RESULT", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "SQL_CALC_FOUND_ROWS", "SQLEXCEPTION", "SQL_SMALL_RESULT", "SQLSTATE", "SQLWARNING", "SSL", "STARTING", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
"STRAIGHT_JOIN", //$NON-NLS-1$
- "TABLE", "TABLES", "TERMINATED", "TEXT", "THEN", "TIME", "TIMESTAMP", "TINYBLOB", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "TINYINT", "TINYTEXT", "TO", "TRAILING", "TRIGGER", "TRUE", "UNDO", "UNION", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "UNIQUE", "UNLOCK", "UNSIGNED", "UPDATE", "UPGRADE", "USAGE", "USE", "USING", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", "VALUES", "VARBINARY", "VARCHAR", "VARCHARACTER", "VARYING", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "WHEN", "WHERE", "WHILE", "WITH", "WRITE", "X509", "XOR", "YEAR_MONTH", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
- "ZEROFILL" }; //$NON-NLS-1$
+ "TABLE", "TABLES", "TERMINATED", "TEXT", "THEN", "TIME", "TIMESTAMP", "TINYBLOB", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "TINYINT", "TINYTEXT", "TO", "TRAILING", "TRIGGER", "TRUE", "UNDO", "UNION", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "UNIQUE", "UNLOCK", "UNSIGNED", "UPDATE", "UPGRADE", "USAGE", "USE", "USING", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", "VALUES", "VARBINARY", "VARCHAR", "VARCHARACTER", "VARYING", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "WHEN", "WHERE", "WHILE", "WITH", "WRITE", "X509", "XOR", "YEAR_MONTH", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "ZEROFILL" }; //$NON-NLS-1$
public MYSQLAdapter()
{
@@ -161,4 +164,16 @@ public class MYSQLAdapter extends DBAdapter
{
return "ALTER TABLE " + tableName + " MODIFY " + fieldName + " " + definition;
}
+
+ @Override
+ public Connection modifyConnection(Connection connection)
+ {
+ if (connection instanceof ConnectionProperties)
+ {
+ ConnectionProperties connectionProperties = (ConnectionProperties)connection;
+ connectionProperties.setUseLocalSessionState(true);
+ }
+
+ return super.modifyConnection(connection);
+ }
}
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/BatchedStatement.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/BatchedStatement.java
new file mode 100644
index 0000000000..624d6e6a09
--- /dev/null
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/BatchedStatement.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.net4j.db;
+
+import java.sql.PreparedStatement;
+
+/**
+ * @since 4.5
+ * @author Eike Stepper
+ * @noextend This interface is not intended to be extended by clients.
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface BatchedStatement extends PreparedStatement
+{
+ public int getBatchSize();
+
+ public int getBatchCount();
+
+ public int getTotalResult();
+}
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBUtil.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBUtil.java
index 647f1efe56..f3c1a4b9eb 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBUtil.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBUtil.java
@@ -14,6 +14,7 @@ import org.eclipse.net4j.db.ddl.IDBField;
import org.eclipse.net4j.db.ddl.IDBNamedElement;
import org.eclipse.net4j.db.ddl.IDBSchema;
import org.eclipse.net4j.db.ddl.IDBTable;
+import org.eclipse.net4j.internal.db.BatchedStatementImpl;
import org.eclipse.net4j.internal.db.DBConnection;
import org.eclipse.net4j.internal.db.DBDatabase;
import org.eclipse.net4j.internal.db.DataSourceConnectionProvider;
@@ -376,6 +377,14 @@ public final class DBUtil
return IDBAdapter.REGISTRY.get(adapterName);
}
+ /**
+ * @since 4.5
+ */
+ public static BatchedStatement batched(PreparedStatement delegate, int batchSize) throws DBException
+ {
+ return new BatchedStatementImpl(delegate, batchSize);
+ }
+
public static Exception close(ResultSet resultSet)
{
if (resultSet != null)
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBAdapter.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBAdapter.java
index a4fe9b7dfa..571f676f1c 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBAdapter.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBAdapter.java
@@ -60,6 +60,11 @@ public interface IDBAdapter
public IDBConnectionProvider createConnectionProvider(DataSource dataSource);
/**
+ * @since 4.5
+ */
+ public Connection modifyConnection(Connection connection);
+
+ /**
* @since 4.2
*/
public IDBSchema readSchema(Connection connection, String name);
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/BatchedStatementImpl.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/BatchedStatementImpl.java
new file mode 100644
index 0000000000..c022c64634
--- /dev/null
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/BatchedStatementImpl.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.net4j.internal.db;
+
+import org.eclipse.net4j.db.BatchedStatement;
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.jdbc.DelegatingPreparedStatement;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+/**
+ * @author Eike Stepper
+ * @since 4.5
+ */
+public final class BatchedStatementImpl extends DelegatingPreparedStatement implements BatchedStatement
+{
+ private final int batchSize;
+
+ private int batchCount;
+
+ private int totalResult;
+
+ public BatchedStatementImpl(PreparedStatement delegate, int batchSize) throws DBException
+ {
+ super(delegate, getConnection(delegate));
+ this.batchSize = batchSize;
+ }
+
+ public int getBatchSize()
+ {
+ return batchSize;
+ }
+
+ public int getBatchCount()
+ {
+ return batchCount;
+ }
+
+ public int getTotalResult()
+ {
+ return totalResult;
+ }
+
+ @Override
+ public int executeUpdate() throws SQLException
+ {
+ PreparedStatement delegate = getDelegate();
+ delegate.addBatch();
+
+ if (++batchCount >= batchSize)
+ {
+ return doExecuteBatch();
+ }
+
+ return 0;
+ }
+
+ @Override
+ public void close() throws SQLException
+ {
+ if (batchCount != 0)
+ {
+ doExecuteBatch();
+ }
+
+ super.close();
+ }
+
+ @Override
+ public ResultSet getResultSet() throws SQLException
+ {
+ throw new UnsupportedOperationException("Only updates are supported");
+ }
+
+ @Override
+ public ResultSet executeQuery() throws SQLException
+ {
+ throw new UnsupportedOperationException("Only updates are supported");
+ }
+
+ @Deprecated
+ @Override
+ public ResultSet executeQuery(String sql) throws SQLException
+ {
+ throw new UnsupportedOperationException("Only updates are supported");
+ }
+
+ private int doExecuteBatch() throws SQLException
+ {
+ int sum = 0;
+
+ int[] results = getDelegate().executeBatch();
+ for (int i = 0; i < results.length; i++)
+ {
+ int result = results[i];
+ if (result != Statement.SUCCESS_NO_INFO)
+ {
+ if (result < 0)
+ {
+ throw new DBException("Result " + i + " is not successful: " + result);
+ }
+
+ sum += result;
+ }
+ }
+
+ totalResult += sum;
+ return sum;
+ }
+
+ private static Connection getConnection(PreparedStatement delegate) throws DBException
+ {
+ try
+ {
+ return delegate.getConnection();
+ }
+ catch (SQLException ex)
+ {
+ throw new DBException(ex);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java
index da9434e860..72665bb84c 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java
@@ -33,7 +33,7 @@ import java.util.LinkedList;
/**
* @author Eike Stepper
*/
-public final class DBDatabase extends SetContainer<IDBConnection>implements IDBDatabase
+public final class DBDatabase extends SetContainer<IDBConnection> implements IDBDatabase
{
private DBAdapter adapter;
@@ -142,6 +142,8 @@ public final class DBDatabase extends SetContainer<IDBConnection>implements IDBD
throw new DBException("No connection from connection provider: " + connectionProvider);
}
+ delegate = adapter.modifyConnection(delegate);
+
DBConnection connection = new DBConnection(this, delegate);
addElement(connection);
return connection;
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBPreparedStatement.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBPreparedStatement.java
index 295fb361da..b5af459ed8 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBPreparedStatement.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBPreparedStatement.java
@@ -22,7 +22,7 @@ import java.sql.SQLException;
/**
* @author Eike Stepper
*/
-public final class DBPreparedStatement extends DelegatingPreparedStatement implements IDBPreparedStatement
+public class DBPreparedStatement extends DelegatingPreparedStatement implements IDBPreparedStatement
{
private final String sql;
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBAdapter.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBAdapter.java
index fbd52b6c73..c50be818e5 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBAdapter.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBAdapter.java
@@ -144,6 +144,14 @@ public abstract class DBAdapter implements IDBAdapter
}
/**
+ * @since 4.5
+ */
+ public Connection modifyConnection(Connection connection)
+ {
+ return connection;
+ }
+
+ /**
* @since 4.2
*/
public IDBSchema readSchema(Connection connection, String name)
diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/buffer/BufferInputStream.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/buffer/BufferInputStream.java
index 52ab739f85..ca3e4b6f74 100644
--- a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/buffer/BufferInputStream.java
+++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/buffer/BufferInputStream.java
@@ -40,6 +40,9 @@ public class BufferInputStream extends InputStream implements IBufferHandler
public static final long DEFAULT_MILLIS_INTERRUPT_CHECK = 100;
+ private static final boolean DISABLE_TIMEOUT = Boolean
+ .getBoolean("org.eclipse.net4j.buffer.BufferInputStream.disableTimeout");
+
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_BUFFER_STREAM, BufferInputStream.class);
private final boolean tracerEnabled;
@@ -205,7 +208,7 @@ public class BufferInputStream extends InputStream implements IBufferHandler
}
long timeout;
- if (noTimeout)
+ if (noTimeout || DISABLE_TIMEOUT)
{
timeout = check;
}
@@ -240,6 +243,11 @@ public class BufferInputStream extends InputStream implements IBufferHandler
private long computeTimeout(final long check) throws IOTimeoutException
{
+ if (DISABLE_TIMEOUT)
+ {
+ return Integer.MAX_VALUE;
+ }
+
long remaining;
synchronized (this)
{

Back to the top