NewObjectCreationRaceTest.java :  » Net » Terracotta » com » tctest » Java Open Source

Java Open Source » Net » Terracotta 
Terracotta » com » tctest » NewObjectCreationRaceTest.java
/*
 * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice.  All rights reserved.
 */
package com.tctest;

import EDU.oswego.cs.dl.util.concurrent.CyclicBarrier;
import EDU.oswego.cs.dl.util.concurrent.SynchronizedRef;

import com.tc.object.config.ConfigVisitor;
import com.tc.object.config.DSOClientConfigHelper;
import com.tc.object.config.TransparencyClassSpec;
import com.tc.object.config.spec.CyclicBarrierSpec;
import com.tc.simulator.app.ApplicationConfig;
import com.tc.simulator.listener.ListenerProvider;
import com.tc.util.Assert;
import com.tctest.runner.AbstractErrorCatchingTransparentApp;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class NewObjectCreationRaceTest extends TransparentTestBase {

  private static final int NODE_COUNT = 3;

  public void setUp() throws Exception {
    super.setUp();
    getTransparentAppConfig().setClientCount(NODE_COUNT).setIntensity(1);
    initializeTestRunner();
  }

  protected Class getApplicationClass() {
    return NewObjectCreationRaceTestApp.class;
  }

  public static class NewObjectCreationRaceTestApp extends AbstractErrorCatchingTransparentApp {

    // NOTE: it is very important to NOT reference
    // this root in the "fault" nodes, until after it has the new object in it
    private Map                 root;

    private final CyclicBarrier barrier;

    public NewObjectCreationRaceTestApp(String appId, ApplicationConfig cfg, ListenerProvider listenerProvider) {
      super(appId, cfg, listenerProvider);

      if (getParticipantCount() < 2) { throw new AssertionError("need at least two nodes for this test to work"); }

      barrier = new CyclicBarrier(getParticipantCount());
    }

    protected void runTest() throws Throwable {
      int n = barrier.barrier();

      if (n == 0) {
        runCreateNode();
      } else {
        runFaultNode();
      }
    }

    private void runFaultNode() throws Exception {
      barrier.barrier();

      final Map faultedRoot;

      // fault the root under the same lock it was modified under
      // this avoids a ConcurrentModificationException
      synchronized (barrier) {
        faultedRoot = root;
      }

      for (Iterator i = faultedRoot.entrySet().iterator(); i.hasNext();) {
        Map.Entry entry = (Entry) i.next();
        Object key = entry.getKey();
        System.out.println(key);
        Object value = entry.getValue();
        System.out.println(value);

        if (value instanceof Ref) {
          Object ref = ((Ref) value).getRef();
          System.out.println(ref);
        }
      }

      // unblock the create node
      barrier.barrier();

      // wait for the create node to commit it's change
      barrier.barrier();

      // make sure the delta is in there
      synchronized (faultedRoot) {
        Object o = faultedRoot.get("delta");
        Assert.assertEquals("non-null", o);
        Assert.assertEquals(5, faultedRoot.size());
      }
    }

    private void runCreateNode() throws Throwable {
      final SynchronizedRef error = new SynchronizedRef(null);

      // create root in this node only
      root = new HashMap();

      final Object newObj = new Object();
      final Ref newRefToOtherNewObject = new Ref(new Object());

      synchronized (root) {
        root.put("delta", null);
        root.put("new object", newObj);
        root.put("new ref to new obj", newRefToOtherNewObject);

        Runnable otherTxn = new Runnable() {
          public void run() {
            try {
              synchronized (barrier) {
                root.put("ref to new with ref to created", new Ref(newObj));
                root.put("ref to created with ref to created", newRefToOtherNewObject);
              }
            } catch (Throwable err) {
              error.set(err);
            }
          }
        };

        Thread t1 = new Thread(otherTxn);
        t1.start();
        t1.join();

        checkError(error);

        // unblock the "fault" nodes. Need to do this in another thread so that the
        // TXN the current thread is in doesn't commit()
        Runnable doBarrier = new Runnable() {
          public void run() {
            try {
              barrier.barrier();
            } catch (Throwable err) {
              error.set(err);
            }
          }
        };
        Thread t2 = new Thread(doBarrier);
        t2.start();
        t2.join();

        checkError(error);

        // block at least until the other node(s) cause the problematic fault. This also needs to be done in another
        // thread so that this thread's TXN does not commit
        Thread t3 = new Thread(doBarrier);
        t3.start();
        t3.join();

        checkError(error);

        // create a change (ie. delta DNA) in the original transaction
        root.put("delta", "non-null");

        barrier.barrier();
      }

    }

    private void checkError(SynchronizedRef error) throws Throwable {
      Throwable t = (Throwable) error.get();
      if (t != null) { throw t; }
    }

    public static void visitL1DSOConfig(ConfigVisitor visitor, DSOClientConfigHelper config) {
      new CyclicBarrierSpec().visit(visitor, config);

      String testClass;
      TransparencyClassSpec spec;
      String methodExpression;

      testClass = Ref.class.getName();
      spec = config.getOrCreateSpec(testClass);

      testClass = NewObjectCreationRaceTest.class.getName();
      spec = config.getOrCreateSpec(testClass);
      methodExpression = "* " + testClass + "*.*(..)";
      config.addWriteAutolock(methodExpression);

      config.addIncludePattern(testClass + "$*");

      testClass = NewObjectCreationRaceTestApp.class.getName();
      spec = config.getOrCreateSpec(testClass);

      methodExpression = "* " + testClass + "*.*(..)";
      config.addWriteAutolock(methodExpression);
      spec.addRoot("barrier", "barrier");
      spec.addRoot("root", "root");
    }

  }

  private static class Ref {
    private final Object ref;

    Ref(Object ref) {
      this.ref = ref;
    }

    Object getRef() {
      return ref;
    }
  }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.