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 positional write 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 PwriteDirect
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 /**
50  * Testing FileChannel's positional write method.
51  */
52 public class PwriteDirect {
53 
54     private static Random generator = RandomFactory.getRandom();
55 
56     private static int charsPerGroup = -1;
57 
58     private static int alignment = -1;
59 
initTests()60     private static boolean initTests() throws Exception {
61         Path p = DirectIOTest.createTempFile();
62         if (!DirectIOTest.isDirectIOSupportedByFS(p)) {
63             Files.delete(p);
64             return false;
65         }
66         try {
67             FileStore fs = Files.getFileStore(p);
68             alignment = (int)fs.getBlockSize();
69             charsPerGroup = alignment;
70         } finally {
71             Files.delete(p);
72         }
73         return true;
74     }
75 
main(String[] args)76     public static void main(String[] args) throws Exception {
77         if (initTests()) {
78             genericTest();
79             TestWithNotAlignedChannelPosition();
80             testUnwritableChannel();
81         }
82     }
83 
testUnwritableChannel()84     private static void testUnwritableChannel() throws Exception {
85         Path p = DirectIOTest.createTempFile();
86 
87         try (FileChannel fc = FileChannel.open(p,
88             StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
89             try {
90                 fc.write(ByteBuffer.allocate(charsPerGroup), 0);
91                 throw new RuntimeException("Expected exception not thrown");
92             } catch(NonWritableChannelException e) {
93                 // Correct result
94             }
95         }
96     }
97 
TestWithNotAlignedChannelPosition()98     private static void TestWithNotAlignedChannelPosition() throws Exception {
99         Path p = DirectIOTest.createTempFile();
100 
101         try (FileChannel fc = FileChannel.open(p,
102             StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
103             int bufferSize = charsPerGroup;
104             long position = charsPerGroup - 1;
105             try {
106                 fc.write(ByteBuffer.allocate(bufferSize), position);
107                 throw new RuntimeException("Expected exception not thrown");
108             } catch(IOException e) {
109                 if (!e.getMessage().contains("Channel position (" + position + ")"
110                     + " is not a multiple of the block size (" + alignment + ")"))
111                     throw new RuntimeException("Write test failed");
112             }
113         }
114     }
115 
genericTest()116     private static void genericTest() throws Exception {
117         Path p = DirectIOTest.createTempFile();
118 
119         initTestFile(p);
120 
121         try (FileChannel fc = FileChannel.open(p,
122             StandardOpenOption.READ, StandardOpenOption.WRITE,
123             StandardOpenOption.DELETE_ON_CLOSE, ExtendedOpenOption.DIRECT)) {
124             ByteBuffer block =
125                 ByteBuffer.allocateDirect(charsPerGroup + alignment - 1)
126                           .alignedSlice(alignment);
127             for (int x = 0; x < 100; x++) {
128                 block.clear();
129                 long offset = generator.nextInt(100) * charsPerGroup;
130 
131                 // Write known sequence out
132                 for (int i = 0; i < charsPerGroup; i++) {
133                     block.put(i, (byte)'a');
134                 }
135                 long originalPosition = fc.position();
136 
137                 int written = fc.write(block, offset);
138                 if (written < 0)
139                     throw new Exception("Write failed");
140 
141                 long newPosition = fc.position();
142 
143                 // Ensure that file pointer position has not changed
144                 if (originalPosition != newPosition)
145                     throw new Exception("File position modified");
146 
147                 // Attempt to read sequence back in
148                 originalPosition = fc.position();
149 
150                 block.rewind();
151                 int read = fc.read(block, offset);
152                 if (read != charsPerGroup)
153                     throw new Exception("Read failed");
154 
155                 newPosition = fc.position();
156 
157                 // Ensure that file pointer position has not changed
158                 if (originalPosition != newPosition)
159                     throw new Exception("File position modified");
160 
161                 for (int j = 0; j < charsPerGroup; j++) {
162                     if (block.get(j) != (byte)'a')
163                         throw new Exception("Write test failed");
164                 }
165             }
166         }
167     }
168 
initTestFile(Path p)169     private static void initTestFile(Path p) throws Exception {
170         try (OutputStream fos = Files.newOutputStream(p)) {
171             try (BufferedWriter awriter
172                 = new BufferedWriter(new OutputStreamWriter(fos, "8859_1"))) {
173                 for (int i = 0; i < 100; i++) {
174                     String number = new Integer(i).toString();
175                     for (int h = 0; h < 4 - number.length(); h++)
176                         awriter.write("0");
177                     awriter.write("" + i);
178                     for (int j = 0; j < 4092; j++)
179                         awriter.write("0");
180                 }
181                 awriter.flush();
182             }
183         }
184     }
185 }
186