| /* |
| * Copyright (c) 2012 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.CDOLock; |
| import org.eclipse.emf.cdo.eresource.CDOResource; |
| import org.eclipse.emf.cdo.eresource.CDOResourceFolder; |
| import org.eclipse.emf.cdo.eresource.CDOResourceNode; |
| import org.eclipse.emf.cdo.session.CDOSession; |
| import org.eclipse.emf.cdo.tests.AbstractCDOTest; |
| import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; |
| import org.eclipse.emf.cdo.transaction.CDOTransaction; |
| import org.eclipse.emf.cdo.util.CommitException; |
| |
| import org.eclipse.net4j.util.io.IOUtil; |
| |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.TimeoutException; |
| |
| /** |
| * @author Eike Stepper |
| */ |
| public class Bugzilla_353448_Test extends AbstractCDOTest |
| { |
| private static final long TIMEOUT = 5 * 1000; |
| |
| private static final String BASE_PREFIX = "baseFolder"; |
| |
| private static final String MODEL1 = "company1Models"; |
| |
| private static final String MODEL2 = "company2Models"; |
| |
| private static final String MODEL1_PREFIX = BASE_PREFIX + "/" + MODEL1; |
| |
| private static int TOTAL_JOBS_NUMBER = 5; |
| |
| private CDOSession session; |
| |
| @Requires(IRepositoryConfig.CAPABILITY_UNAVAILABLE) |
| public void testDuplicateEntry() throws Exception |
| { |
| bootStrapPaths(); |
| |
| final Exception[] exception = { null }; |
| final CountDownLatch latch = new CountDownLatch(TOTAL_JOBS_NUMBER); |
| for (int i = 0; i < TOTAL_JOBS_NUMBER; i++) |
| { |
| final IPath p = new Path("/Project1/SubProject1/" + i % 4 + "/" + i); |
| new Thread("Create Resource Job") |
| { |
| @Override |
| public void run() |
| { |
| msg("Commiting " + MODEL1_PREFIX + p); |
| TransactionDelegateMock delegate = null; |
| |
| try |
| { |
| delegate = new TransactionDelegateMock(session.openTransaction(), new Path("/" + MODEL1_PREFIX + p)); |
| CommitException commitEx = null; |
| |
| for (int j = 0; j < 10; j++) |
| { |
| try |
| { |
| delegate.resource.getContents().add(getModel1Factory().createOrderDetail()); |
| delegate.transaction.commit(); |
| msg("END OF COMMIT " + MODEL1_PREFIX + p); |
| return; |
| } |
| catch (CommitException ex) |
| { |
| delegate.transaction.rollback(); |
| commitEx = ex; |
| |
| // Try again |
| sleep(200L); |
| } |
| } |
| |
| throw commitEx; |
| } |
| catch (Exception ex) |
| { |
| IOUtil.print(ex); |
| if (exception[0] == null) |
| { |
| exception[0] = ex; |
| } |
| } |
| finally |
| { |
| latch.countDown(); |
| if (delegate != null) |
| { |
| delegate.transaction.close(); |
| } |
| } |
| } |
| }.start(); |
| } |
| |
| if (!latch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS)) |
| { |
| throw new TimeoutException(); |
| } |
| |
| if (exception[0] != null) |
| { |
| throw exception[0]; |
| } |
| } |
| |
| private void bootStrapPaths() throws CommitException |
| { |
| session = openSession(); |
| CDOTransaction transaction = session.openTransaction(); |
| |
| try |
| { |
| transaction.getResourceNode(getResourcePath(BASE_PREFIX)); |
| } |
| catch (Exception e) |
| { |
| CDOResourceFolder base = transaction.createResourceFolder(getResourcePath(BASE_PREFIX)); |
| base.addResourceFolder(MODEL1); |
| base.addResourceFolder(MODEL2); |
| |
| try |
| { |
| transaction.commit(); |
| } |
| finally |
| { |
| transaction.close(); |
| } |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private class TransactionDelegateMock |
| { |
| private final CDOTransaction transaction; |
| |
| private final CDOResource resource; |
| |
| public TransactionDelegateMock(CDOTransaction transaction, IPath path) throws Exception |
| { |
| this.transaction = transaction; |
| resource = getResource(path, transaction); |
| } |
| |
| private synchronized CDOResource getResource(IPath path2, CDOTransaction transaction2) throws Exception |
| { |
| if (!transaction2.hasResource(getResourcePath(path2.toString()))) |
| { |
| // only if resource does not exists |
| String[] segments = path2.segments(); |
| CDOResourceNode resourceNode = null; |
| for (int i = 0; i < segments.length; i++) |
| { |
| String curPath = path2.uptoSegment(i).toString(); |
| if (!existsResourceNode(transaction2, curPath)) |
| { |
| assert resourceNode != null : "The base resource nodes should have been bootstrapped"; |
| CDOLock lock = resourceNode.cdoWriteLock(); |
| |
| if (lock.tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) |
| { |
| if (!existsResourceNode(transaction2, curPath)) |
| { |
| msg("Adding resource folder " + curPath + " curThread " + Thread.currentThread()); |
| resourceNode = transaction2.createResourceFolder(getResourcePath(curPath)); |
| transaction2.commit(); |
| } |
| else |
| { |
| resourceNode = transaction2.getResourceNode(getResourcePath(curPath)); |
| } |
| } |
| } |
| else |
| { |
| resourceNode = transaction2.getResourceNode(getResourcePath(curPath)); |
| msg("Path Exists " + curPath + " OID " + resourceNode.cdoID()); |
| } |
| } |
| |
| resourceNode = transaction2.getResourceNode(getResourcePath(path2.removeLastSegments(1).toString())); |
| if (resourceNode.cdoWriteLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) |
| { |
| CDOResource rez = transaction2.createResource(getResourcePath(path2.toString())); |
| transaction2.commit(); |
| return rez; |
| } |
| } |
| |
| return transaction2.getResource(getResourcePath(path2.toString())); |
| } |
| |
| private boolean existsResourceNode(CDOTransaction transaction, String path) |
| { |
| try |
| { |
| return transaction.getResourceNode(getResourcePath(path)) != null; |
| } |
| catch (Exception e) |
| { |
| return false; |
| } |
| } |
| } |
| } |