/* * 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.spi.checkpoint.sharedfs; import java.io.File; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.testframework.junits.spi.GridSpiAbstractTest; import org.apache.ignite.testframework.junits.spi.GridSpiTest; import org.apache.ignite.testframework.junits.spi.GridSpiTestConfig; import org.jetbrains.annotations.Nullable; /** * Tests SPI in multi-threaded environment. */ @GridSpiTest(spi = SharedFsCheckpointSpi.class, group = "Checkpoint SPI") public class GridSharedFsCheckpointSpiMultiThreadedSelfTest extends GridSpiAbstractTest<SharedFsCheckpointSpi> { /** */ private static final String PATH = "work/cp/test-shared-fs-multi-threaded"; /** */ private static final String CHECK_POINT_KEY = "testCheckpoint"; /** */ private static final int ARRAY_SIZE = 1024 * 1024; /** */ private static final int ITER_CNT = 100; /** */ private static final int THREAD_CNT = 10; /** * @return Paths. */ @GridSpiTestConfig(setterName="setDirectoryPaths") public Collection<String> getDirectoryPaths() { return Collections.singleton(PATH); } /** * * @throws Exception If failed. */ public void testSpi() throws Exception { final AtomicInteger writeFinished = new AtomicInteger(); final AtomicBoolean fail = new AtomicBoolean(); IgniteInternalFuture fut1 = GridTestUtils.runMultiThreadedAsync( new Callable<Object>() { @Nullable @Override public Object call() throws Exception { try { byte[] state = createTestArray((byte)1); for (int i = 0; i < ITER_CNT; i++) getSpi().saveCheckpoint(CHECK_POINT_KEY, state, 0, true); return null; } finally { writeFinished.incrementAndGet(); } } }, THREAD_CNT, "writer-1" ); IgniteInternalFuture fut2 = GridTestUtils.runMultiThreadedAsync( new Callable<Object>() { @Nullable @Override public Object call() throws Exception { try{ byte[] state = createTestArray((byte)2); for (int i = 0; i < ITER_CNT; i++) getSpi().saveCheckpoint(CHECK_POINT_KEY, state, 0, true); return null; } finally { writeFinished.incrementAndGet(); } } }, THREAD_CNT, "writer-2" ); IgniteInternalFuture fut3 = GridTestUtils.runMultiThreadedAsync( new Callable<Object>() { @Nullable @Override public Object call() throws Exception { while (writeFinished.get() < THREAD_CNT * 2) { try { byte[] state = getSpi().loadCheckpoint(CHECK_POINT_KEY); if (state == null) continue; assert state.length == ARRAY_SIZE; boolean has1 = false; boolean has2 = false; for (int j = 0; j < ARRAY_SIZE; j++) { switch (state[j]) { case 1: has1 = true; assert !has2; break; case 2: has2 = true; assert !has1; break; default: assert false : "Unexpected value in state: " + state[j]; } } info(">>>>>>> Checkpoint is fine."); } catch (Throwable e) { error("Failed to load checkpoint: " + e.getMessage()); fail.set(true); } } return null; } }, 1, "reader" ); fut1.get(); fut2.get(); fut3.get(); assert !fail.get(); } /** * @param val Val to fill with. * @return Test array. */ private byte[] createTestArray(byte val) { byte[] res = new byte[ARRAY_SIZE]; Arrays.fill(res, val); return res; } /** * @param f Folder to delete. */ void deleteFolder(File f) { for (File file : f.listFiles()) if (file.isDirectory()) deleteFolder(file); else file.delete(); f.delete(); } /** {@inheritDoc} */ @Override protected void afterTestsStopped() throws Exception { super.afterTestsStopped(); deleteFolder(new File(U.getIgniteHome(), PATH)); } }