| /* |
| * 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.ignite.lang.utils; |
| |
| import java.util.Iterator; |
| import java.util.NoSuchElementException; |
| import java.util.concurrent.CyclicBarrier; |
| import java.util.concurrent.locks.ReentrantLock; |
| import org.apache.ignite.internal.util.GridStripedLock; |
| import org.apache.ignite.testframework.GridTestUtils; |
| import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; |
| import org.junit.Test; |
| |
| /** |
| * |
| */ |
| public class GridStripedLockSelfTest extends GridCommonAbstractTest { |
| /** */ |
| private static final int STRIPE_COUNT = 16; |
| |
| /** */ |
| private static final long ITERATION_COUNT = STRIPE_COUNT * 10000; |
| |
| /** */ |
| private static final int THREAD_COUNT = STRIPE_COUNT * 4; |
| |
| /** */ |
| private GridStripedLock lock; |
| |
| /** */ |
| private CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT); |
| |
| /** {@inheritDoc} */ |
| @Override protected void beforeTest() throws Exception { |
| lock = new GridStripedLock(STRIPE_COUNT); |
| |
| barrier = new CyclicBarrier(THREAD_COUNT); |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testIntLocking() throws Exception { |
| GridTestUtils.runMultiThreaded(new Runnable() { |
| @Override public void run() { |
| try { |
| barrier.await(); |
| } |
| catch (Exception e) { |
| fail("Failed to await other threads: " + e.getMessage()); |
| } |
| |
| for (int i = 0; i < STRIPE_COUNT * 10000; i++) { |
| lock.lock(i); |
| |
| try { |
| int holdCnt = 0; |
| |
| for (int lockNum = 0; lockNum < STRIPE_COUNT; lockNum++) |
| if (((ReentrantLock)lock.getLock(lockNum)).isHeldByCurrentThread()) |
| holdCnt++; |
| |
| assertEquals(1, holdCnt); |
| } |
| finally { |
| lock.unlock(i); |
| } |
| } |
| } |
| }, THREAD_COUNT, "GridStripedLock-test"); |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testLongLocking() throws Exception { |
| GridTestUtils.runMultiThreaded(new Runnable() { |
| @Override public void run() { |
| try { |
| barrier.await(); |
| } |
| catch (Exception e) { |
| fail("Failed to await other threads: " + e.getMessage()); |
| } |
| |
| for (long i = Integer.MAX_VALUE; i < ITERATION_COUNT + Integer.MAX_VALUE; i++) { |
| lock.lock(i); |
| |
| try { |
| int holdCnt = 0; |
| |
| for (long lockNum = 0; lockNum < STRIPE_COUNT; lockNum++) |
| if (((ReentrantLock)lock.getLock(lockNum)).isHeldByCurrentThread()) |
| holdCnt++; |
| |
| assertEquals(1, holdCnt); |
| } |
| finally { |
| lock.unlock(i); |
| } |
| } |
| } |
| }, THREAD_COUNT, "GridStripedLock-test"); |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testObjectLocking() throws Exception { |
| GridTestUtils.runMultiThreaded(new Runnable() { |
| @Override public void run() { |
| try { |
| barrier.await(); |
| } |
| catch (Exception e) { |
| fail("Failed to await other threads: " + e.getMessage()); |
| } |
| |
| for (Object o : testObjects((int)ITERATION_COUNT)) { |
| lock.lock(o); |
| |
| try { |
| int holdCnt = 0; |
| |
| for (Object lockObject : testObjects(STRIPE_COUNT)) |
| if (((ReentrantLock)lock.getLock(lockObject)).isHeldByCurrentThread()) |
| holdCnt++; |
| |
| // null object considered 0-hash code, so they should appear twicely. |
| if (o == null || o.hashCode() % STRIPE_COUNT == 0) |
| assertEquals(2, holdCnt); |
| else |
| assertEquals("Test object " + o.hashCode(), 1, holdCnt); |
| } |
| finally { |
| lock.unlock(o); |
| } |
| } |
| } |
| }, THREAD_COUNT, "GridStripedLock-test"); |
| } |
| |
| /** |
| * Returns iterable containing required number of objects with consequent hashCodes starting from 0 |
| * and one {@code null} element. |
| * |
| * @param cnt Objects count. |
| * @return Iterable instance. |
| */ |
| private Iterable<Object> testObjects(final int cnt) { |
| assert cnt >= 2; |
| |
| return new Iterable<Object>() { |
| @Override public Iterator<Object> iterator() { |
| return new Iterator<Object>() { |
| private int curr = -1; |
| |
| @Override public boolean hasNext() { |
| return curr < cnt; |
| } |
| |
| @Override public Object next() { |
| curr++; |
| |
| if (curr > cnt) |
| throw new NoSuchElementException(); |
| |
| return curr == 0 ? |
| null : |
| new Object() { |
| private final int code = curr - 1; |
| |
| @Override public int hashCode() { |
| return code; |
| } |
| }; |
| } |
| |
| @Override public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| }; |
| } |
| }; |
| } |
| } |