1 /* 2 * Copyright (c) 2017, 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 * @bug 8164900 26 * @summary Test read method of FileChannel with DirectIO 27 * (use -Dseed=X to set PRNG seed) 28 * @library .. /test/lib 29 * @build jdk.test.lib.RandomFactory 30 * DirectIOTest 31 * @run main/othervm ReadDirect 32 * @key randomness 33 */ 34 35 import java.io.*; 36 import java.nio.ByteBuffer; 37 import java.nio.CharBuffer; 38 import java.nio.channels.*; 39 import java.nio.file.Files; 40 import java.nio.file.FileStore; 41 import java.nio.file.Path; 42 import java.nio.file.Paths; 43 import java.nio.file.StandardOpenOption; 44 import java.util.Random; 45 import com.sun.nio.file.ExtendedOpenOption; 46 47 import jdk.test.lib.RandomFactory; 48 49 public class ReadDirect { 50 51 private static PrintStream err = System.err; 52 53 private static Random generator = RandomFactory.getRandom(); 54 55 private static int charsPerGroup = -1; 56 57 private static int alignment = -1; 58 initTests()59 private static boolean initTests() throws Exception { 60 Path p = DirectIOTest.createTempFile(); 61 if (!DirectIOTest.isDirectIOSupportedByFS(p)) { 62 Files.delete(p); 63 return false; 64 } 65 try { 66 FileStore fs = Files.getFileStore(p); 67 alignment = (int)fs.getBlockSize(); 68 charsPerGroup = alignment; 69 } finally { 70 Files.delete(p); 71 } 72 return true; 73 } 74 testWithSingleBuffer()75 private static void testWithSingleBuffer() throws Exception { 76 StringBuffer sb = new StringBuffer(); 77 sb.setLength(2); 78 79 Path p = DirectIOTest.createTempFile(); 80 81 initTestFile(p); 82 try (FileChannel fc = FileChannel.open(p, 83 StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE, 84 ExtendedOpenOption.DIRECT)) { 85 ByteBuffer block = ByteBuffer.allocateDirect(charsPerGroup 86 + alignment - 1).alignedSlice(alignment); 87 for (int x = 0; x < 100; x++) { 88 block.clear(); 89 long offset = x * charsPerGroup; 90 long expectedResult = offset / charsPerGroup; 91 fc.read(block); 92 93 for (int i = 0; i < 2; i++) { 94 byte aByte = block.get(i); 95 sb.setCharAt(i, (char)aByte); 96 } 97 int result = Integer.parseInt(sb.toString()); 98 if (result != expectedResult) { 99 err.println("I expected " + expectedResult); 100 err.println("I got " + result); 101 throw new Exception("Read test failed"); 102 } 103 } 104 } 105 } 106 testWithNotAlignedBufferSize()107 private static void testWithNotAlignedBufferSize() throws Exception { 108 int bufferSize = charsPerGroup - 1; 109 Path p = DirectIOTest.createTempFile(); 110 111 try (OutputStream fos = Files.newOutputStream(p)) { 112 fos.write(new byte[bufferSize]); 113 } 114 115 try (FileChannel fc = FileChannel.open(p, 116 StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE, 117 ExtendedOpenOption.DIRECT)) { 118 ByteBuffer block = ByteBuffer.allocate(bufferSize); 119 try { 120 fc.read(block); 121 throw new RuntimeException("Expected exception not thrown"); 122 } catch (IOException e) { 123 if (!e.getMessage().contains("Number of remaining bytes (" 124 + bufferSize + ") is not a multiple of the block size (" 125 + alignment + ")")) 126 throw new Exception("Read test failed"); 127 } 128 } 129 } 130 testWithNotAlignedBufferOffset()131 private static void testWithNotAlignedBufferOffset() throws Exception { 132 int bufferSize = charsPerGroup * 2; 133 int pos = alignment - 1; 134 135 Path p = DirectIOTest.createTempFile(); 136 137 try (OutputStream fos = Files.newOutputStream(p)) { 138 fos.write(new byte[bufferSize]); 139 } 140 141 try (FileChannel fc = FileChannel.open(p, 142 StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE, 143 ExtendedOpenOption.DIRECT)) { 144 ByteBuffer block = ByteBuffer.allocateDirect(bufferSize); 145 block.position(pos); 146 block.limit(bufferSize - 1); 147 try { 148 fc.read(block); 149 throw new RuntimeException("Expected exception not thrown"); 150 } catch (IOException e) { 151 if (!e.getMessage().contains("Current location of the bytebuffer " 152 + "(" + pos + ") is not a multiple of the block size (" 153 + alignment + ")")) 154 throw new Exception("Read test failed"); 155 } 156 } 157 } 158 testWithArrayOfBuffer()159 private static void testWithArrayOfBuffer() throws Exception { 160 StringBuffer sb = new StringBuffer(); 161 sb.setLength(2); 162 ByteBuffer[] dests = new ByteBuffer[4]; 163 Path p = DirectIOTest.createTempFile(); 164 165 initTestFile(p); 166 167 try (FileChannel fc = FileChannel.open(p, 168 StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE, 169 ExtendedOpenOption.DIRECT)) { 170 int randomNumber = -1; 171 172 for (int i = 0; i < 4; i++) { 173 dests[i] = ByteBuffer.allocateDirect 174 (charsPerGroup + alignment - 1).alignedSlice(alignment); 175 for (int j = 0; j < charsPerGroup; j++) { 176 dests[i].put(j, (byte)'a'); 177 } 178 } 179 180 // The size of the test FileChannel is 100*charsPerGroup. 181 // As the channel bytes will be scattered into two buffers 182 // each of size charsPerGroup, the offset cannot be greater 183 // than 98*charsPerGroup, so the value of randomNumber must 184 // be in the range [0,98], i.e., 0 <= randomNumber < 99. 185 randomNumber = generator.nextInt(99); 186 long offset = randomNumber * charsPerGroup; 187 fc.position(offset); 188 fc.read(dests, 1, 2); 189 190 for (int i = 0; i < 4; i++) { 191 if (i == 1 || i == 2) { 192 for (int j = 0; j < 2; j++) { 193 byte aByte = dests[i].get(j); 194 sb.setCharAt(j, (char)aByte); 195 } 196 int result = Integer.parseInt(sb.toString()); 197 int expectedResult = randomNumber + i - 1; 198 if (result != expectedResult) { 199 err.println("I expected " + expectedResult); 200 err.println("I got " + result); 201 throw new Exception("Read test failed"); 202 } 203 } else { 204 for (int k = 0; k < charsPerGroup; k++) { 205 if (dests[i].get(k) != (byte)'a') 206 throw new RuntimeException("Read test failed"); 207 } 208 } 209 } 210 } 211 } 212 testOnEOF()213 public static void testOnEOF() throws Exception { 214 int bufferSize = charsPerGroup / 2; 215 Path p = DirectIOTest.createTempFile(); 216 217 try (OutputStream fos = Files.newOutputStream(p)) { 218 byte[] writeBlock = new byte[bufferSize]; 219 for (int i = 0; i < bufferSize; i++) { 220 writeBlock[i] = ((byte)'a'); 221 } 222 fos.write(writeBlock); 223 } 224 225 try (FileChannel fc = FileChannel.open(p, 226 StandardOpenOption.READ, StandardOpenOption.DELETE_ON_CLOSE, 227 ExtendedOpenOption.DIRECT)) { 228 ByteBuffer block = ByteBuffer.allocateDirect( 229 (bufferSize / alignment + 1) * alignment + alignment - 1) 230 .alignedSlice(alignment); 231 int result = fc.read(block); 232 if (result != bufferSize) { 233 err.println("Number of bytes to read " + bufferSize); 234 err.println("I read " + result); 235 throw new Exception("Read test failed"); 236 } 237 for (int j = 0; j < bufferSize; j++) { 238 if (block.get(j) != (byte)'a') 239 throw new RuntimeException("Read test failed"); 240 } 241 } 242 } 243 main(String[] args)244 public static void main(String[] args) throws Exception { 245 if (initTests()) { 246 testWithSingleBuffer(); 247 testWithNotAlignedBufferSize(); 248 testWithNotAlignedBufferOffset(); 249 testWithArrayOfBuffer(); 250 testOnEOF(); 251 } 252 } 253 initTestFile(Path p)254 private static void initTestFile(Path p) 255 throws Exception { 256 try (OutputStream fos = Files.newOutputStream(p)) { 257 try (BufferedWriter awriter 258 = new BufferedWriter(new OutputStreamWriter(fos, "8859_1"))) { 259 for (int i = 0; i < 100; i++) { 260 String number = new Integer(i).toString(); 261 for (int h = 0; h < 2 - number.length(); h++) 262 awriter.write("0"); 263 awriter.write("" + i); 264 for (int j = 0; j < (charsPerGroup - 2); j++) 265 awriter.write("0"); 266 } 267 awriter.flush(); 268 } 269 } 270 } 271 } 272