diff --git a/config/alfresco/dao/dao-context.xml b/config/alfresco/dao/dao-context.xml
index 6fa9cc4e44..74e81924ab 100644
--- a/config/alfresco/dao/dao-context.xml
+++ b/config/alfresco/dao/dao-context.xml
@@ -145,6 +145,9 @@
+
+
+
diff --git a/source/java/org/alfresco/repo/domain/hibernate/dialect/AlfrescoMySQLClusterNDBDialect.java b/source/java/org/alfresco/repo/domain/hibernate/dialect/AlfrescoMySQLClusterNDBDialect.java
new file mode 100644
index 0000000000..74e714a243
--- /dev/null
+++ b/source/java/org/alfresco/repo/domain/hibernate/dialect/AlfrescoMySQLClusterNDBDialect.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2005-2016 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.domain.hibernate.dialect;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.dialect.MySQLInnoDBDialect;
+
+/**
+ * MySQL Cluster NDB specific DAO overrides
+ *
+ * WARNING:
+ * - Experimental only (unsupported) !
+ * - The NDB storage engine is *not* currently supported or certified !
+ * - Can be used for dev/test evaluation (please give us feedback)
+ * - Should not be used for live/prod env with real data !
+ * - Requires FK support (hence NDB 7.3.x or higher)
+ *
+ * @author janv
+ *
+ */
+//note: *not* a dialect of InnoDB but, for now, extends here so that we can override those scripts
+public class AlfrescoMySQLClusterNDBDialect extends MySQLInnoDBDialect
+{
+ protected Log logger = LogFactory.getLog(AlfrescoMySQLClusterNDBDialect.class);
+
+ public AlfrescoMySQLClusterNDBDialect()
+ {
+ super();
+
+ logger.error("Using NDB with Alfresco is experimental and unsupported (do not use for live/prod envs) !");
+ }
+
+ public String getTableTypeString() {
+ return " engine=NDB";
+ }
+
+}
diff --git a/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java
index b6524205d1..11ff333f77 100644
--- a/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java
+++ b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2013 Alfresco Software Limited.
+ * Copyright (C) 2005-2016 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -1390,6 +1390,37 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
if (!allowAuditableAspect) addAuditableAspect = false;
+ Long id = newNodeImplInsert(node);
+ node.setId(id);
+
+ Set nodeAspects = null;
+ if (addAuditableAspect)
+ {
+ Long auditableAspectQNameId = qnameDAO.getOrCreateQName(ContentModel.ASPECT_AUDITABLE).getFirst();
+ insertNodeAspect(id, auditableAspectQNameId);
+ nodeAspects = Collections.singleton(ContentModel.ASPECT_AUDITABLE);
+ }
+ else
+ {
+ nodeAspects = Collections.emptySet();
+ }
+
+ // Lock the node and cache
+ node.lock();
+ nodesCache.setValue(id, node);
+ // Pre-populate some of the other caches so that we don't immediately query
+ setNodeAspectsCached(id, nodeAspects);
+ setNodePropertiesCached(id, Collections.emptyMap());
+
+ if (isDebugEnabled)
+ {
+ logger.debug("Created new node: \n" + " " + node);
+ }
+ return node;
+ }
+
+ protected Long newNodeImplInsert(NodeEntity node)
+ {
Long id = null;
Savepoint savepoint = controlDAO.createSavepoint("newNodeImpl");
try
@@ -1425,32 +1456,8 @@ public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO
throw new NodeExistsException(dbTargetNode.getNodePair(), e);
}
}
- node.setId(id);
- Set nodeAspects = null;
- if (addAuditableAspect)
- {
- Long auditableAspectQNameId = qnameDAO.getOrCreateQName(ContentModel.ASPECT_AUDITABLE).getFirst();
- insertNodeAspect(id, auditableAspectQNameId);
- nodeAspects = Collections.singleton(ContentModel.ASPECT_AUDITABLE);
- }
- else
- {
- nodeAspects = Collections.emptySet();
- }
-
- // Lock the node and cache
- node.lock();
- nodesCache.setValue(id, node);
- // Pre-populate some of the other caches so that we don't immediately query
- setNodeAspectsCached(id, nodeAspects);
- setNodePropertiesCached(id, Collections.emptyMap());
-
- if (isDebugEnabled)
- {
- logger.debug("Created new node: \n" + " " + node);
- }
- return node;
+ return id;
}
@Override
diff --git a/source/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java b/source/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java
index 5b7fa1f121..14ef4fb2b9 100644
--- a/source/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java
+++ b/source/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2011 Alfresco Software Limited.
+ * Copyright (C) 2005-2016 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -28,6 +28,7 @@ import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
+import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.ibatis.IdsEntity;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.node.AbstractNodeDAOImpl;
@@ -37,6 +38,7 @@ import org.alfresco.repo.domain.node.Node;
import org.alfresco.repo.domain.node.NodeAspectsEntity;
import org.alfresco.repo.domain.node.NodeAssocEntity;
import org.alfresco.repo.domain.node.NodeEntity;
+import org.alfresco.repo.domain.node.NodeExistsException;
import org.alfresco.repo.domain.node.NodeIdAndAclId;
import org.alfresco.repo.domain.node.NodePropertyEntity;
import org.alfresco.repo.domain.node.NodePropertyKey;
@@ -1719,7 +1721,7 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
}
/**
- * MySQL-specific DAO overrides
+ * MySQL (InnoDB) specific DAO overrides
*/
public static class MySQL extends NodeDAOImpl
{
@@ -1743,6 +1745,58 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
return numDeleted;
}
}
+
+ /**
+ * MySQL Cluster NDB specific DAO overrides
+ *
+ * WARNING: Experimental/unsupported - see AlfrescoMySQLClusterNDBDialect !
+ *
+ * @author janv
+ */
+ public static class MySQLClusterNDB extends MySQL
+ {
+ @Override
+ protected Long newNodeImplInsert(NodeEntity node)
+ {
+ Long id = null;
+ try
+ {
+ // We need to handle existing deleted nodes.
+ NodeRef targetNodeRef = node.getNodeRef();
+ Node dbTargetNode = selectNodeByNodeRef(targetNodeRef);
+ if (dbTargetNode != null)
+ {
+ if (dbTargetNode.getDeleted(qnameDAO))
+ {
+ Long dbTargetNodeId = dbTargetNode.getId();
+ // This is OK. It happens when we create a node that existed in the past.
+ // Remove the row completely
+ deleteNodeProperties(dbTargetNodeId, (Set) null);
+ deleteNodeById(dbTargetNodeId);
+ }
+ else
+ {
+ // A live node exists.
+ throw new NodeExistsException(dbTargetNode.getNodePair(), null);
+ }
+ }
+
+ id = insertNode(node);
+ }
+ catch (Throwable e)
+ {
+ if (e instanceof NodeExistsException)
+ {
+ throw e;
+ }
+
+ // There does not appear to be any row that could prevent an insert
+ throw new AlfrescoRuntimeException("Failed to insert new node: " + node, e);
+ }
+
+ return id;
+ }
+ }
/**
* Get most recent transaction made in a given commit time range
diff --git a/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java b/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java
index fca4415545..de477ee0c3 100644
--- a/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java
+++ b/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2005-2015 Alfresco Software Limited.
-
+ * Copyright (C) 2005-2016 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -70,6 +69,7 @@ import org.alfresco.repo.admin.patch.AppliedPatch;
import org.alfresco.repo.admin.patch.Patch;
import org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch;
import org.alfresco.repo.content.filestore.FileContentWriter;
+import org.alfresco.repo.domain.hibernate.dialect.AlfrescoMySQLClusterNDBDialect;
import org.alfresco.repo.domain.hibernate.dialect.AlfrescoOracle9Dialect;
import org.alfresco.repo.domain.hibernate.dialect.AlfrescoSQLServerDialect;
import org.alfresco.repo.domain.hibernate.dialect.AlfrescoSybaseAnywhereDialect;
@@ -1478,6 +1478,23 @@ public class SchemaBootstrap extends AbstractLifecycleBean
sql = sql.replaceAll("(?i)TYPE=InnoDB", "ENGINE=InnoDB");
}
+ if (this.dialect != null && this.dialect instanceof AlfrescoMySQLClusterNDBDialect)
+ {
+ // note: enable bootstrap on MySQL Cluster NDB
+ /*
+ * WARNING: Experimental/unsupported - see AlfrescoMySQLClusterNDBDialect !
+ */
+ sql = sql.replaceAll("(?i)TYPE=InnoDB", "ENGINE=NDB"); // belts-and-braces
+ sql = sql.replaceAll("(?i)ENGINE=InnoDB", "ENGINE=NDB");
+
+ sql = sql.replaceAll("(?i) BIT ", " BOOLEAN ");
+ sql = sql.replaceAll("(?i) BIT,", " BOOLEAN,");
+
+ sql = sql.replaceAll("(?i) string_value text", " string_value VARCHAR(1024)");
+
+ sql = sql.replaceAll("(?i) VARCHAR(4000)", "TEXT(4000)");
+ }
+
Object fetchedVal = executeStatement(connection, sql, fetchColumnName, optional, line, scriptFile);
if (fetchVarName != null && fetchColumnName != null)
{
@@ -1635,6 +1652,12 @@ public class SchemaBootstrap extends AbstractLifecycleBean
// serializable_value blob,
maxStringLength = Integer.MAX_VALUE;
}
+ else if (dialect instanceof AlfrescoMySQLClusterNDBDialect)
+ {
+ // string_value varchar(1024),
+ // serializable_value blob,
+ maxStringLength = SchemaBootstrap.DEFAULT_MAX_STRING_LENGTH;
+ }
else if (dialect instanceof AlfrescoOracle9Dialect)
{
// string_value varchar2(1024 char),
diff --git a/source/java/org/alfresco/repo/domain/schema/script/ScriptExecutorImpl.java b/source/java/org/alfresco/repo/domain/schema/script/ScriptExecutorImpl.java
index 3996fbde8b..190f74aeb8 100644
--- a/source/java/org/alfresco/repo/domain/schema/script/ScriptExecutorImpl.java
+++ b/source/java/org/alfresco/repo/domain/schema/script/ScriptExecutorImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2014 Alfresco Software Limited.
+ * Copyright (C) 2005-2016 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -35,6 +35,7 @@ import javax.sql.DataSource;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.filestore.FileContentWriter;
+import org.alfresco.repo.domain.hibernate.dialect.AlfrescoMySQLClusterNDBDialect;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.util.LogUtil;
import org.alfresco.util.TempFileProvider;
@@ -537,6 +538,23 @@ public class ScriptExecutorImpl implements ScriptExecutor
sql = sql.replaceAll("(?i)TYPE=InnoDB", "ENGINE=InnoDB");
}
+ if (this.dialect != null && this.dialect instanceof AlfrescoMySQLClusterNDBDialect)
+ {
+ // note: enable bootstrap on MySQL Cluster NDB
+ /*
+ * WARNING: Experimental/unsupported - see AlfrescoMySQLClusterNDBDialect !
+ */
+ sql = sql.replaceAll("(?i)TYPE=InnoDB", "ENGINE=NDB"); // belts-and-braces
+ sql = sql.replaceAll("(?i)ENGINE=InnoDB", "ENGINE=NDB");
+
+ sql = sql.replaceAll("(?i) BIT ", " BOOLEAN ");
+ sql = sql.replaceAll("(?i) BIT,", " BOOLEAN,");
+
+ sql = sql.replaceAll("(?i) string_value text", " string_value VARCHAR(1024)");
+
+ sql = sql.replaceAll("(?i) VARCHAR(4000)", "TEXT(4000)");
+ }
+
Object fetchedVal = executeStatement(connection, sql, fetchColumnName, optional, line, scriptFile);
if (fetchVarName != null && fetchColumnName != null)
{
diff --git a/source/test-java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java b/source/test-java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java
index df36e050a5..57d3fd7d16 100644
--- a/source/test-java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java
+++ b/source/test-java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005-2014 Alfresco Software Limited.
+ * Copyright (C) 2005-2016 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -916,6 +916,8 @@ public class ArchiveAndRestoreTest extends TestCase
RestoreNodeReport report = nodeArchiveService.restoreArchivedNode(r_);
assertEquals("Restore failed", RestoreStatus.SUCCESS, report.getStatus());
+ commitAndBeginNewTransaction();
+
//It is restored, still with no AUDITABLE ASPECT
verifyNodeExistence(r, true);
verifyAspectExistence(r, ContentModel.ASPECT_AUDITABLE, false);