Return-Path: X-Original-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Delivered-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 951941046A for ; Tue, 7 May 2013 09:42:40 +0000 (UTC) Received: (qmail 96057 invoked by uid 500); 7 May 2013 09:42:40 -0000 Delivered-To: apmail-jackrabbit-oak-commits-archive@jackrabbit.apache.org Received: (qmail 95978 invoked by uid 500); 7 May 2013 09:42:38 -0000 Mailing-List: contact oak-commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: oak-dev@jackrabbit.apache.org Delivered-To: mailing list oak-commits@jackrabbit.apache.org Received: (qmail 95948 invoked by uid 99); 7 May 2013 09:42:37 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 07 May 2013 09:42:37 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 07 May 2013 09:42:34 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id ED6B12388847; Tue, 7 May 2013 09:42:12 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1479832 - /jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/ConcurrentConflictTest.java Date: Tue, 07 May 2013 09:42:12 -0000 To: oak-commits@jackrabbit.apache.org From: mreutegg@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130507094212.ED6B12388847@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: mreutegg Date: Tue May 7 09:42:12 2013 New Revision: 1479832 URL: http://svn.apache.org/r1479832 Log: OAK-619 Lock-free MongoMK implementation - Additional conflict test (currently fails and is ignored) Added: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/ConcurrentConflictTest.java (with props) Added: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/ConcurrentConflictTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/ConcurrentConflictTest.java?rev=1479832&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/ConcurrentConflictTest.java (added) +++ jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/ConcurrentConflictTest.java Tue May 7 09:42:12 2013 @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.mongomk; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.jackrabbit.mk.api.MicroKernel; +import org.apache.jackrabbit.mk.api.MicroKernelException; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.assertEquals; + +/** + * ConcurrentConflictTest... + */ +public class ConcurrentConflictTest extends BaseMongoMKTest { + + private static final boolean USE_LOGGER = true; + private static final Logger log = LoggerFactory.getLogger(ConcurrentConflictTest.class); + private static final int NUM_WRITERS = 3; + private static final int NUM_NODES = 10; + private static final int NUM_TRANSFERS_PER_THREAD = 10; + private DocumentStore store; + private List kernels = new ArrayList(); + private final StringBuilder logBuffer = new StringBuilder(); + + @Before + public void setup() { + logBuffer.setLength(0); + this.store = new MemoryDocumentStore(); + MongoMK mk = openMongoMK(); + for (int i = 0; i < NUM_NODES; i++) { + mk.commit("/", "+\"node-" + i + "\":{\"value\":100}", null, null); + } + for (int i = 0; i < NUM_WRITERS; i++) { + kernels.add(openMongoMK()); + } + } + + private MongoMK openMongoMK() { + return new MongoMK.Builder().setAsyncDelay(10).setDocumentStore(store).open(); + } + + @Ignore + @Test + public void concurrentUpdatesWithBranch() throws Exception { + concurrentUpdates(true); + } + + @Ignore + @Test + public void concurrentUpdates() throws Exception { + concurrentUpdates(false); + } + + private void concurrentUpdates(final boolean useBranch) throws Exception { + log.info("====== Start test ======="); + final AtomicInteger conflicts = new AtomicInteger(); + final List exceptions = Collections.synchronizedList( + new ArrayList()); + List writers = new ArrayList(); + for (final MicroKernel mk : kernels) { + writers.add(new Thread(new Runnable() { + Random random = new Random(); + Map nodes = new HashMap(); + @Override + public void run() { + BitSet conflictSet = new BitSet(); + int numTransfers = NUM_TRANSFERS_PER_THREAD; + try { + while (numTransfers > 0) { + try { + if (!transfer()) { + continue; + } + } catch (MicroKernelException e) { + log("Failed transfer @" + mk.getHeadRevision()); + // assume conflict + conflicts.incrementAndGet(); + conflictSet.set(numTransfers); + } + numTransfers--; + } + } catch (Exception e) { + exceptions.add(e); + } + log("conflicts: " + conflictSet); + } + + private boolean transfer() throws Exception { + // read 3 random nodes and re-distribute values + nodes.clear(); + while (nodes.size() < 3) { + nodes.put(random.nextInt(NUM_NODES), null); + } + String rev; + if (useBranch) { + rev = mk.branch(null); + } else { + rev = mk.getHeadRevision(); + } + int sum = 0; + for (Map.Entry entry : nodes.entrySet()) { + String json = mk.getNodes("/node-" + entry.getKey(), rev, 0, 0, 1000, null); + JSONParser parser = new JSONParser(); + JSONObject obj = (JSONObject) parser.parse(json); + entry.setValue(obj); + sum += (Long) obj.get("value"); + } + if (sum < 60) { + // retry with other nodes + return false; + } + StringBuilder jsop = new StringBuilder(); + boolean withdrawn = false; + for (Map.Entry entry : nodes.entrySet()) { + long value = (Long) entry.getValue().get("value"); + jsop.append("^\"/node-").append(entry.getKey()); + jsop.append("/value\":"); + if (value >= 20 && ! withdrawn) { + jsop.append(value - 20); + withdrawn = true; + } else { + jsop.append(value + 10); + } + } + String oldRev = rev; + rev = mk.commit("", jsop.toString(), rev, null); + if (useBranch) { + rev = mk.merge(rev, null); + } + log("Successful transfer @" + oldRev + ": " + jsop.toString() + " (new rev: " + rev + ")"); + return true; + } + })); + } + for (Thread t : writers) { + t.start(); + } + for (Thread t : writers) { + t.join(); + } + // dispose will flush all pending revisions + for (MongoMK mk : kernels) { + mk.dispose(); + } + MongoMK mk = openMongoMK(); + String rev = mk.getHeadRevision(); + long sum = 0; + for (int i = 0; i < NUM_NODES; i++) { + String json = mk.getNodes("/node-" + i, rev, 0, 0, 1000, null); + JSONParser parser = new JSONParser(); + JSONObject obj = (JSONObject) parser.parse(json); + sum += (Long) obj.get("value"); + } + log("Conflict rate: " + conflicts.get() + + "/" + (NUM_WRITERS * NUM_TRANSFERS_PER_THREAD)); + System.out.print(logBuffer); + assertEquals(NUM_NODES * 100, sum); + if (!exceptions.isEmpty()) { + throw exceptions.get(0); + } + } + + private void log(String msg) { + if (USE_LOGGER) { + log.info(msg); + } else { + synchronized (logBuffer) { + logBuffer.append(msg).append("\n"); + } + } + } +} Propchange: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/ConcurrentConflictTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/ConcurrentConflictTest.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL