1 /*
2  * Copyright (c) 2015, 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 /*
25  * @test
26  * @bug 4823133
27  * @summary optimize RandomAccessFile.length() and length() is thread safe now.
28  */
29 import java.io.File;
30 import java.io.FileNotFoundException;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.io.RandomAccessFile;
34 
35 /**
36  *
37  * @author vyom.tewari@oracle.com
38  */
39 public class FileLengthTest {
40 
41     private static final int BUF_SIZE = 4096;
42     private static RandomAccessFile randomAccessFile;
43     private static Thread fileLengthCaller;
44     private static Thread fileContentReader;
45     private static StringBuilder fileContents;
46     private static volatile boolean isFailed = false;
47 
48     /**
49      * this thread will call length() in loop
50      */
startLengthThread()51     private static void startLengthThread() {
52         if (randomAccessFile == null) {
53             return;
54         }
55         fileLengthCaller = new Thread(() -> {
56             while (true) {
57                 try {
58                     long length = randomAccessFile.length();
59                     if (length < 0) {
60                         return;
61                     }
62                 } catch (IOException ex) {
63                     return;
64                 }
65             }
66         });
67         fileLengthCaller.setName("RandomAccessFile-length-caller");
68         fileLengthCaller.setDaemon(true);
69         fileLengthCaller.start();
70     }
71 
72     /**
73      * this thread will call read() and store the content in internal buffer.
74      */
startReaderThread()75     private static void startReaderThread() {
76         if (randomAccessFile == null) {
77             return;
78         }
79         fileContentReader = new Thread(() -> {
80             StringBuilder sb = new StringBuilder(BUF_SIZE);
81             int i;
82             byte arr[] = new byte[8];
83             try {
84                 while ((i = randomAccessFile.read(arr)) != -1) {
85                     sb.append(new String(arr, 0, i));
86                 }
87                 if (!sb.toString().equals(fileContents.toString())) {
88                     isFailed = true;
89                 }
90             } catch (IOException ex) {
91             }
92         });
93         fileContentReader.setName("RandomAccessFile-content-reader");
94         fileContentReader.setDaemon(true);
95         fileContentReader.start();
96     }
97 
main(String args[])98     public static void main(String args[]) {
99         byte arr[] = new byte[BUF_SIZE];
100         String testFile = "testfile.txt";
101         try {
102             createDummyFile(testFile);
103             File file = new File(testFile);
104             file.deleteOnExit();
105             randomAccessFile = new RandomAccessFile(file, "r");
106             int count = randomAccessFile.read(arr);
107             randomAccessFile.seek(0);
108             fileContents = new StringBuilder(BUF_SIZE);
109             fileContents.append(new String(arr, 0, count));
110             startLengthThread();
111             startReaderThread();
112             fileContentReader.join();
113         } catch (FileNotFoundException | InterruptedException ex) {
114         } catch (IOException ex) {
115         } finally {
116             try {
117                 randomAccessFile.close();
118             } catch (IOException ex) {
119             }
120         }
121         if (isFailed) {
122             throw new RuntimeException("RandomAccessFile.length() changed the underlying file pointer.");
123         }
124     }
125 
createDummyFile(String fileName)126     private static void createDummyFile(String fileName) throws FileNotFoundException, IOException {
127         try (FileOutputStream outputStream = new FileOutputStream(new File(fileName))) {
128             String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
129             int count = 0;
130             while ((count + str.length()) < BUF_SIZE) {
131                 outputStream.write(str.getBytes());
132                 count += str.length();
133             }
134             outputStream.flush();
135         }
136     }
137 }
138