/*
* 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.internal.util.ipc.shmem;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteSystemProperties;
import org.apache.ignite.internal.IgniteInternalFuture;
import org.apache.ignite.internal.util.lang.GridAbsPredicate;
import org.apache.ignite.testframework.GridTestUtils;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
import org.jsr166.ThreadLocalRandom8;
/**
*
*/
public class IpcSharedMemorySpaceSelfTest extends GridCommonAbstractTest {
/** */
public static final int DATA_LEN = 1024 * 1024;
/** */
private static final byte[] DATA = new byte[DATA_LEN];
/**
*
*/
static {
for (int i = 0; i < DATA_LEN; i++)
DATA[i] = (byte)i;
}
/** {@inheritDoc} */
@Override protected void beforeTestsStarted() throws Exception {
super.beforeTestsStarted();
IpcSharedMemoryNativeLoader.load(log());
}
/**
* @throws Exception If failed.
*/
public void testBasicOperations() throws Exception {
File tokFile = new File(IgniteSystemProperties.getString("java.io.tmpdir"), UUID.randomUUID().toString());
assert tokFile.createNewFile();
final String tok = tokFile.getAbsolutePath();
info("Array length: " + DATA.length);
final AtomicReference<IpcSharedMemorySpace> spaceRef = new AtomicReference<>();
IgniteInternalFuture<?> fut1 = multithreadedAsync(
new Callable<Object>() {
@SuppressWarnings("TooBroadScope")
@Override public Object call() throws Exception {
try (IpcSharedMemorySpace space = new IpcSharedMemorySpace(tok, 0, 0, 128, false,
log)) {
spaceRef.set(space);
int bytesWritten = 0;
for (; ; ) {
int len = Math.min(DATA.length - bytesWritten,
ThreadLocalRandom8.current().nextInt(256) + 1);
space.write(DATA, bytesWritten, len, 0);
bytesWritten += len;
if (bytesWritten == DATA.length)
break;
}
info("Thread finished.");
return null;
}
}
},
1,
"writer");
IgniteInternalFuture<?> fut2 = multithreadedAsync(
new Callable<Object>() {
@SuppressWarnings({"TooBroadScope", "StatementWithEmptyBody"})
@Override public Object call() throws Exception {
IpcSharedMemorySpace inSpace;
GridTestUtils.waitForCondition(new GridAbsPredicate() {
@Override public boolean apply() {
return spaceRef.get() != null;
}
}, 10_000);
inSpace = spaceRef.get();
assertNotNull(inSpace);
try (IpcSharedMemorySpace space = new IpcSharedMemorySpace(tok, 0, 0, 128, true,
inSpace.sharedMemoryId(), log)) {
byte[] buf = new byte[DATA_LEN];
int bytesRead = 0;
for (; ; ) {
int len = Math.min(DATA.length - bytesRead,
ThreadLocalRandom8.current().nextInt(32) + 1);
int len0 = space.read(buf, bytesRead, len, 0);
assert len0 > 0;
bytesRead += len0;
if (bytesRead == DATA_LEN)
break;
}
assertTrue(Arrays.equals(DATA, buf));
return null;
}
}
},
1,
"reader");
fut1.get();
fut2.get();
assert !tokFile.exists();
}
/**
* @throws Exception If failed.
*/
public void testForceClose() throws Exception {
File tokFile = new File(IgniteSystemProperties.getString("java.io.tmpdir"), getTestIgniteInstanceName());
assert tokFile.createNewFile() || tokFile.exists();
String tok = tokFile.getAbsolutePath();
info("Using token file: " + tok);
Collection<Integer> ids = IpcSharedMemoryUtils.sharedMemoryIds();
info("IDs in the system: " + ids);
IpcSharedMemorySpace space = new IpcSharedMemorySpace(tok, IpcSharedMemoryUtils.pid(), 0, 128,
false, log);
ids = IpcSharedMemoryUtils.sharedMemoryIds();
info("IDs in the system: " + ids);
assert ids.contains(space.sharedMemoryId());
// Write some data to the space, but avoid blocking.
space.write(DATA, 0, 16, 0);
int shmemId = space.sharedMemoryId();
space.forceClose();
ids = IpcSharedMemoryUtils.sharedMemoryIds();
info("IDs in the system: " + ids);
assert !ids.contains(shmemId);
assert !tokFile.exists();
}
/**
* @throws Exception If failed.
*/
public void testReadAfterClose() throws Exception {
File tokFile = new File(IgniteSystemProperties.getString("java.io.tmpdir"), getTestIgniteInstanceName());
assert tokFile.createNewFile() || tokFile.exists();
String tok = tokFile.getAbsolutePath();
info("Using token file: " + tok);
IpcSharedMemorySpace spaceOut = new IpcSharedMemorySpace(tok, IpcSharedMemoryUtils.pid(), 0, 128,
false, log);
try (IpcSharedMemorySpace spaceIn = new IpcSharedMemorySpace(tok, IpcSharedMemoryUtils.pid(), 0,
128, true, spaceOut.sharedMemoryId(), log)) {
// Write some data to the space, but avoid blocking.
spaceOut.write(DATA, 0, 16, 0);
spaceOut.close();
// Read after other party has already called "close()".
// Space has data available and should read it.
byte[] buf = new byte[16];
int len = spaceIn.read(buf, 0, 16, 0);
assert len == 16;
len = spaceIn.read(buf, 0, 16, 0);
assert len == -1;
}
assert !tokFile.exists();
}
/**
* @throws Exception If failed.
*/
public void testWriteAfterClose() throws Exception {
File tokFile = new File(IgniteSystemProperties.getString("java.io.tmpdir"), getTestIgniteInstanceName());
assert tokFile.createNewFile() || tokFile.exists();
String tok = tokFile.getAbsolutePath();
info("Using token file: " + tok);
try (IpcSharedMemorySpace spaceOut = new IpcSharedMemorySpace(tok, IpcSharedMemoryUtils.pid(),
IpcSharedMemoryUtils.pid(), 128, false, log)) {
try (IpcSharedMemorySpace spaceIn = new IpcSharedMemorySpace(tok, IpcSharedMemoryUtils.pid(),
IpcSharedMemoryUtils.pid(), 128, true, spaceOut.sharedMemoryId(), log)) {
// Write some data to the space, but avoid blocking.
spaceOut.write(DATA, 0, 16, 0);
spaceIn.close();
try {
spaceOut.write(DATA, 0, 16, 0);
assert false;
}
catch (IgniteCheckedException e) {
info("Caught expected exception: " + e);
}
}
}
assert !tokFile.exists();
}
}