1 /*
   2  * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test
  25  * @ignore This test has huge disk space requirements
  26  * @bug 8168628
  27  * @summary Test extending files to very large sizes without hitting a SIGBUS
  28  * @requires (os.family == "linux")
  29  * @run main/othervm/timeout=600 -Xms4g -Xmx4g FileExtensionAndMap
  30  * @run main/othervm/timeout=600 -Xms4g -Xmx4g FileExtensionAndMap true
  31  */
  32 
  33 import java.io.File;
  34 import java.io.IOException;
  35 import java.io.RandomAccessFile;
  36 import java.nio.MappedByteBuffer;
  37 import java.nio.channels.ClosedChannelException;
  38 import java.nio.channels.FileChannel;
  39 import java.nio.channels.FileChannel.MapMode;
  40 import java.nio.file.Files;
  41 import java.nio.file.Path;
  42 import java.nio.file.Paths;
  43 import java.nio.file.StandardCopyOption;
  44 import java.nio.file.StandardOpenOption;
  45 import java.util.concurrent.ExecutorService;
  46 import java.util.concurrent.Executors;
  47 import java.util.concurrent.ForkJoinPool;
  48 import java.util.concurrent.Semaphore;
  49 import java.util.stream.IntStream;
  50 
  51 public class FileExtensionAndMap {
  52 
  53     private static final ExecutorService CACHED_EXECUTORSERVICE =
  54         Executors.newCachedThreadPool();
  55 
  56     private static final String TMPDIR = System.getProperty("test.dir", ".");
  57 
  58     private static boolean useRaf = false;
  59 
  60     public static void main(String args[]) throws Exception {
  61         if (args.length > 2) {
  62             throw new IllegalArgumentException
  63                 ("Arguments: [true|false [targetFolder]]");
  64         }
  65 
  66         String defaultFolder = TMPDIR + File.separator + "target";
  67         if (args.length > 0) {
  68             useRaf = Boolean.valueOf(args[0]);
  69             if (args.length > 1) {
  70                 defaultFolder = args[1];
  71             }
  72         }
  73         final String targetFolder = defaultFolder;
  74         Path p = Paths.get(targetFolder);
  75         boolean targetExists = Files.exists(p);
  76         if (!targetExists) {
  77             Files.createDirectory(p);
  78         }
  79 
  80         System.out.printf("Using RandomAccessFile: %s; target folder: %s%n",
  81             useRaf, targetFolder);
  82 
  83         ForkJoinPool fjPool = new ForkJoinPool(3);
  84         fjPool.submit(() -> {
  85             IntStream.range(0, 20).parallel().forEach((index) -> {
  86                 String fileName = "testBigFile_" + index + ".dat";
  87                 Path source = null;
  88                 Path target = null;
  89                 try {
  90                     source = Paths.get(TMPDIR, fileName);
  91                     testCreateBigFile(source);
  92                     target = Paths.get(targetFolder, fileName);
  93                     testFileCopy(source, target);
  94                 } catch (Throwable th) {
  95                     System.err.println("Error copying file with fileName: "
  96                         + fileName + " : " + th.getMessage());
  97                     th.printStackTrace(System.err);
  98                 } finally {
  99                     try {
 100                         if (source != null) {
 101                             Files.deleteIfExists(source);
 102                         }
 103                     } catch (Throwable ignored) {
 104                     }
 105                     try {
 106                         if (target != null) {
 107                             Files.deleteIfExists(target);
 108                         }
 109                     } catch (Throwable ignored) {
 110                     }
 111                 }
 112             });
 113         }).join();
 114 
 115         if (!targetExists) {
 116             Files.delete(p);
 117         }
 118     }
 119 
 120     private static void testFileCopy(Path source, Path target)
 121         throws IOException {
 122         Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
 123         System.out.println("Finished copying file with fileName: "
 124                 + source.getFileName());
 125     }
 126 
 127     private static void testCreateBigFile(Path segmentFile)
 128         throws IOException {
 129         final Semaphore concurrencySemaphore = new Semaphore(5);
 130         long fileSize = 3L * 1024L * 1024L * 1024L;
 131         int blockSize = 10 * 1024 * 1024;
 132         int loopCount = (int) Math.floorDiv(fileSize, blockSize);
 133 
 134         String fileName = segmentFile.getFileName().toString();
 135         if (useRaf) {
 136             try (RandomAccessFile raf
 137                 = new RandomAccessFile(segmentFile.toFile(), "rw")) {
 138                 raf.setLength(fileSize);
 139                 try (FileChannel fc = raf.getChannel()) {
 140                     for (int i = 0; i < loopCount; i++) {
 141                         final long startPosition = 1L * blockSize * i;
 142                         concurrencySemaphore.acquireUninterruptibly();
 143                         CACHED_EXECUTORSERVICE.submit(() -> {
 144                             writeTemplateData(fileName, fc, startPosition,
 145                                     blockSize, concurrencySemaphore);
 146                         });
 147                     }
 148                 } finally {
 149                     concurrencySemaphore.acquireUninterruptibly(5);
 150                 }
 151             }
 152         } else {
 153             Path file = Files.createFile(segmentFile);
 154             try (FileChannel fc = FileChannel.open(file,
 155                 StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 156                 for (int i = 0; i < loopCount; i++) {
 157                     final long startPosition = 1L * blockSize * i;
 158                     concurrencySemaphore.acquireUninterruptibly();
 159                     CACHED_EXECUTORSERVICE.submit(() -> {
 160                         writeTemplateData(fileName, fc, startPosition,
 161                                 blockSize, concurrencySemaphore);
 162                     });
 163                 }
 164             }
 165         }
 166     }
 167 
 168     private static void writeTemplateData(String fileName,
 169         FileChannel fc, long startPosition, int blockSize,
 170         Semaphore concurrencySemaphore) {
 171         try {
 172             byte[] EMPTY_RECORD = new byte[blockSize / 256];
 173 
 174             MappedByteBuffer mappedByteBuffer = fc.map(MapMode.READ_WRITE,
 175                 startPosition, blockSize);
 176             IntStream.range(0, 256).forEach((recordIndex) -> {
 177                 try {
 178                     mappedByteBuffer.position((int) (recordIndex *
 179                         EMPTY_RECORD.length));
 180                     mappedByteBuffer.put(EMPTY_RECORD, 0, EMPTY_RECORD.length);
 181                 } catch (Throwable th) {
 182                     System.err.println
 183                         ("Error in FileExtensionAndMap.writeTemplateData empty record for fileName: "
 184                         + fileName + ", startPosition: " + startPosition + ", recordIndex: "
 185                         + recordIndex + " : " + th.getMessage());
 186                     th.printStackTrace(System.err);
 187                 }
 188             });
 189 
 190             mappedByteBuffer.force();
 191         } catch (Throwable th) {
 192             if (!(th instanceof ClosedChannelException)) {
 193                 System.err.println
 194                     ("Error in FileExtensionAndMap.writeTemplateData empty record for fileName: "
 195                     + fileName + ", startPosition: " + startPosition + " : "
 196                     + th.getMessage());
 197                 th.printStackTrace(System.err);
 198             }
 199         } finally {
 200             concurrencySemaphore.release();
 201         }
 202     }
 203 }