/***********************************************************************************************************************
* Copyright (C) 2010-2013 by the Stratosphere project (http://stratosphere.eu)
*
* Licensed 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 eu.stratosphere.nephele.services.iomanager;
import java.io.File;
import java.io.IOException;
import java.util.List;
import junit.framework.Assert;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import eu.stratosphere.core.memory.MemorySegment;
import eu.stratosphere.nephele.services.memorymanager.DefaultMemoryManagerTest.DummyInvokable;
import eu.stratosphere.nephele.services.memorymanager.spi.DefaultMemoryManager;
public class IOManagerTest
{
// ------------------------------------------------------------------------
// Cross Test Fields
// ------------------------------------------------------------------------
private IOManager ioManager;
private DefaultMemoryManager memoryManager;
// ------------------------------------------------------------------------
// Setup & Shutdown
// ------------------------------------------------------------------------
@Before
public void beforeTest()
{
this.memoryManager = new DefaultMemoryManager(32 * 1024 * 1024);
this.ioManager = new IOManager();
}
@After
public void afterTest()
{
this.ioManager.shutdown();
Assert.assertTrue("IO Manager has not properly shut down.", ioManager.isProperlyShutDown());
Assert.assertTrue("Not all memory was returned to the memory manager in the test.", this.memoryManager.verifyEmpty());
this.memoryManager.shutdown();
this.memoryManager = null;
}
// ------------------------------------------------------------------------
// Test Methods
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
/**
* Tests that the channel enumerator creates channels in the temporary files directory.
*/
@Test
public void channelEnumerator() {
File tempPath = new File(System.getProperty("java.io.tmpdir"));
Channel.Enumerator enumerator = ioManager.createChannelEnumerator();
for (int i = 0; i < 10; i++) {
Channel.ID id = enumerator.next();
File path = new File(id.getPath());
Assert.assertTrue("Channel IDs must name an absolute path.", path.isAbsolute());
Assert.assertFalse("Channel IDs must name a file, not a directory.", path.isDirectory());
Assert.assertTrue("Path is not in the temp directory.", tempPath.equals(path.getParentFile()));
}
}
// ------------------------------------------------------------------------
@Test
public void channelReadWriteOneSegment()
{
final int NUM_IOS = 1111;
try {
final Channel.ID channelID = this.ioManager.createChannel();
final BlockChannelWriter writer = this.ioManager.createBlockChannelWriter(channelID);
MemorySegment memSeg = this.memoryManager.allocatePages(new DummyInvokable(), 1).get(0);
for (int i = 0; i < NUM_IOS; i++) {
for (int pos = 0; pos < memSeg.size(); pos += 4) {
memSeg.putInt(pos, i);
}
writer.writeBlock(memSeg);
memSeg = writer.getNextReturnedSegment();
}
writer.close();
final BlockChannelReader reader = this.ioManager.createBlockChannelReader(channelID);
for (int i = 0; i < NUM_IOS; i++) {
reader.readBlock(memSeg);
memSeg = reader.getNextReturnedSegment();
for (int pos = 0; pos < memSeg.size(); pos += 4) {
if (memSeg.getInt(pos) != i) {
Assert.fail("Read memory segment contains invalid data.");
}
}
}
reader.closeAndDelete();
this.memoryManager.release(memSeg);
} catch (Exception ex) {
ex.printStackTrace();
Assert.fail("TEst encountered an exception: " + ex.getMessage());
}
}
@Test
public void channelReadWriteMultipleSegments()
{
final int NUM_IOS = 1111;
final int NUM_SEGS = 16;
try {
final List<MemorySegment> memSegs = this.memoryManager.allocatePages(new DummyInvokable(), NUM_SEGS);
final Channel.ID channelID = this.ioManager.createChannel();
final BlockChannelWriter writer = this.ioManager.createBlockChannelWriter(channelID);
for (int i = 0; i < NUM_IOS; i++) {
final MemorySegment memSeg = memSegs.isEmpty() ? writer.getNextReturnedSegment() : memSegs.remove(0);
for (int pos = 0; pos < memSeg.size(); pos += 4) {
memSeg.putInt(pos, i);
}
writer.writeBlock(memSeg);
}
writer.close();
// get back the memory
while (memSegs.size() < NUM_SEGS) {
memSegs.add(writer.getNextReturnedSegment());
}
final BlockChannelReader reader = this.ioManager.createBlockChannelReader(channelID);
while(!memSegs.isEmpty()) {
reader.readBlock(memSegs.remove(0));
}
for (int i = 0; i < NUM_IOS; i++) {
final MemorySegment memSeg = reader.getNextReturnedSegment();
for (int pos = 0; pos < memSeg.size(); pos += 4) {
if (memSeg.getInt(pos) != i) {
Assert.fail("Read memory segment contains invalid data.");
}
}
reader.readBlock(memSeg);
}
reader.closeAndDelete();
// get back the memory
while (memSegs.size() < NUM_SEGS) {
memSegs.add(reader.getNextReturnedSegment());
}
this.memoryManager.release(memSegs);
} catch (Exception ex) {
ex.printStackTrace();
Assert.fail("TEst encountered an exception: " + ex.getMessage());
}
}
// ============================================================================================
final class FailingSegmentReadRequest implements ReadRequest
{
private final BlockChannelAccess<ReadRequest, ?> channel;
private final MemorySegment segment;
protected FailingSegmentReadRequest(BlockChannelAccess<ReadRequest, ?> targetChannel, MemorySegment segment)
{
this.channel = targetChannel;
this.segment = segment;
}
@Override
public void read() throws IOException
{
throw new TestIOException();
}
@Override
public void requestDone(IOException ioex)
{
this.channel.handleProcessedBuffer(this.segment, ioex);
}
}
//--------------------------------------------------------------------------------------------
/**
* Special write request that writes an entire memory segment to the block writer.
*/
final class FailingSegmentWriteRequest implements WriteRequest
{
private final BlockChannelAccess<WriteRequest, ?> channel;
private final MemorySegment segment;
protected FailingSegmentWriteRequest(BlockChannelAccess<WriteRequest, ?> targetChannel, MemorySegment segment)
{
this.channel = targetChannel;
this.segment = segment;
}
@Override
public void write() throws IOException
{
throw new TestIOException();
}
@Override
public void requestDone(IOException ioex)
{
this.channel.handleProcessedBuffer(this.segment, ioex);
}
}
final class TestIOException extends IOException
{
private static final long serialVersionUID = -814705441998024472L;
}
}