blob: 84feb55cdb77c0c2f1158d6d275d157f92cfbbb9 [file] [log] [blame]
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @ignore This test has huge disk space requirements
* @bug 8168628
* @summary Test extending files to very large sizes without hitting a SIGBUS
* @requires (os.family == "linux")
* @run main/othervm/timeout=600 -Xms4g -Xmx4g FileExtensionAndMap
* @run main/othervm/timeout=600 -Xms4g -Xmx4g FileExtensionAndMap true
*/
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Semaphore;
import java.util.stream.IntStream;
public class FileExtensionAndMap {
private static final ExecutorService CACHED_EXECUTORSERVICE =
Executors.newCachedThreadPool();
private static final String TMPDIR = System.getProperty("test.dir", ".");
private static boolean useRaf = false;
public static void main(String args[]) throws Exception {
if (args.length > 2) {
throw new IllegalArgumentException
("Arguments: [true|false [targetFolder]]");
}
String defaultFolder = TMPDIR + File.separator + "target";
if (args.length > 0) {
useRaf = Boolean.valueOf(args[0]);
if (args.length > 1) {
defaultFolder = args[1];
}
}
final String targetFolder = defaultFolder;
Path p = Paths.get(targetFolder);
boolean targetExists = Files.exists(p);
if (!targetExists) {
Files.createDirectory(p);
}
System.out.printf("Using RandomAccessFile: %s; target folder: %s%n",
useRaf, targetFolder);
ForkJoinPool fjPool = new ForkJoinPool(3);
fjPool.submit(() -> {
IntStream.range(0, 20).parallel().forEach((index) -> {
String fileName = "testBigFile_" + index + ".dat";
Path source = null;
Path target = null;
try {
source = Paths.get(TMPDIR, fileName);
testCreateBigFile(source);
target = Paths.get(targetFolder, fileName);
testFileCopy(source, target);
} catch (Throwable th) {
System.err.println("Error copying file with fileName: "
+ fileName + " : " + th.getMessage());
th.printStackTrace(System.err);
} finally {
try {
if (source != null) {
Files.deleteIfExists(source);
}
} catch (Throwable ignored) {
}
try {
if (target != null) {
Files.deleteIfExists(target);
}
} catch (Throwable ignored) {
}
}
});
}).join();
if (!targetExists) {
Files.delete(p);
}
}
private static void testFileCopy(Path source, Path target)
throws IOException {
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
System.out.println("Finished copying file with fileName: "
+ source.getFileName());
}
private static void testCreateBigFile(Path segmentFile)
throws IOException {
final Semaphore concurrencySemaphore = new Semaphore(5);
long fileSize = 3L * 1024L * 1024L * 1024L;
int blockSize = 10 * 1024 * 1024;
int loopCount = (int) Math.floorDiv(fileSize, blockSize);
String fileName = segmentFile.getFileName().toString();
if (useRaf) {
try (RandomAccessFile raf
= new RandomAccessFile(segmentFile.toFile(), "rw")) {
raf.setLength(fileSize);
try (FileChannel fc = raf.getChannel()) {
for (int i = 0; i < loopCount; i++) {
final long startPosition = 1L * blockSize * i;
concurrencySemaphore.acquireUninterruptibly();
CACHED_EXECUTORSERVICE.submit(() -> {
writeTemplateData(fileName, fc, startPosition,
blockSize, concurrencySemaphore);
});
}
} finally {
concurrencySemaphore.acquireUninterruptibly(5);
}
}
} else {
Path file = Files.createFile(segmentFile);
try (FileChannel fc = FileChannel.open(file,
StandardOpenOption.READ, StandardOpenOption.WRITE)) {
for (int i = 0; i < loopCount; i++) {
final long startPosition = 1L * blockSize * i;
concurrencySemaphore.acquireUninterruptibly();
CACHED_EXECUTORSERVICE.submit(() -> {
writeTemplateData(fileName, fc, startPosition,
blockSize, concurrencySemaphore);
});
}
}
}
}
private static void writeTemplateData(String fileName,
FileChannel fc, long startPosition, int blockSize,
Semaphore concurrencySemaphore) {
try {
byte[] EMPTY_RECORD = new byte[blockSize / 256];
MappedByteBuffer mappedByteBuffer = fc.map(MapMode.READ_WRITE,
startPosition, blockSize);
IntStream.range(0, 256).forEach((recordIndex) -> {
try {
mappedByteBuffer.position((int) (recordIndex *
EMPTY_RECORD.length));
mappedByteBuffer.put(EMPTY_RECORD, 0, EMPTY_RECORD.length);
} catch (Throwable th) {
System.err.println
("Error in FileExtensionAndMap.writeTemplateData empty record for fileName: "
+ fileName + ", startPosition: " + startPosition + ", recordIndex: "
+ recordIndex + " : " + th.getMessage());
th.printStackTrace(System.err);
}
});
mappedByteBuffer.force();
} catch (Throwable th) {
if (!(th instanceof ClosedChannelException)) {
System.err.println
("Error in FileExtensionAndMap.writeTemplateData empty record for fileName: "
+ fileName + ", startPosition: " + startPosition + " : "
+ th.getMessage());
th.printStackTrace(System.err);
}
} finally {
concurrencySemaphore.release();
}
}
}