1 19 package org.netbeans.core.output2; 20 21 import java.util.logging.Logger ; 22 import org.openide.util.NbBundle; 23 24 import java.io.*; 25 import java.nio.ByteBuffer ; 26 import java.nio.channels.FileChannel ; 27 import org.openide.util.Exceptions; 28 29 33 class FileMapStorage implements Storage { 34 35 private FileChannel writeChannel; 36 37 private FileChannel readChannel; 38 40 private static final int BASE_BUFFER_SIZE = 8196; 41 44 private static final long MAX_MAP_RANGE = 1024 * 1024 * 20; 45 51 private ByteBuffer master; 52 54 private ByteBuffer contents; 55 59 private long mappedRange; 60 61 64 private long mappedStart; 65 68 private ByteBuffer buffer = null; 69 72 protected int bytesWritten = 0; 73 76 private File outfile = null; 77 78 private int outstandingBufferCount = 0; 79 80 FileMapStorage() { 81 init(); 82 } 83 84 private void init() { 85 contents = null; 86 mappedRange = -1; 87 mappedStart = 0; 88 master = ByteBuffer.allocateDirect (BASE_BUFFER_SIZE); 89 readChannel = null; 90 writeChannel = null; 91 buffer = null; 92 bytesWritten = 0; 93 } 94 95 98 private void ensureFileExists() throws IOException { 99 if (outfile == null) { 100 String outdir = System.getProperty("java.io.tmpdir"); if (!outdir.endsWith(File.separator)) { 102 outdir += File.separator; 103 } 104 File dir = new File (outdir); 105 if (!dir.exists() || !dir.canWrite()) { 106 IllegalStateException ise = new IllegalStateException ("Cannot" + " write to " + outdir); Exceptions.attachLocalizedMessage(ise, 111 NbBundle.getMessage(OutWriter.class, 112 "FMT_CannotWrite", 113 outdir)); 114 throw ise; 115 } 116 synchronized (FileMapStorage.class) { 119 StringBuilder fname = new StringBuilder (outdir) 120 .append("output").append(Long.toString(System.currentTimeMillis())); outfile = new File (fname.toString()); 122 while (outfile.exists()) { 123 fname.append('x'); outfile = new File(fname.toString()); 125 } 126 outfile.createNewFile(); 127 outfile.deleteOnExit(); 128 } 129 } 130 } 131 132 public String toString() { 133 return outfile == null ? "[unused or disposed FileMapStorage]" : outfile.getPath(); 134 } 135 136 139 private FileChannel writeChannel() { 140 try { 141 if (writeChannel == null) { 142 ensureFileExists(); 143 FileOutputStream fos = new FileOutputStream(outfile, true); 144 writeChannel = fos.getChannel(); 145 } 146 return writeChannel; 147 } catch (FileNotFoundException fnfe) { 148 fnfe.printStackTrace(); } catch (IOException ioe) { 150 ioe.printStackTrace(); } 152 return null; 153 } 154 155 158 private FileChannel readChannel() { 159 if (readChannel == null) { 162 try { 163 ensureFileExists(); 164 FileInputStream fis = new FileInputStream (outfile); 165 readChannel = fis.getChannel(); 166 } catch (Exception e) { 167 e.printStackTrace(); 168 } 169 } 170 return readChannel; 171 } 172 173 177 public synchronized ByteBuffer getWriteBuffer (int size) throws IOException { 178 if (master.capacity() - master.position() < size) { 179 int newSize = Math.max (BASE_BUFFER_SIZE * 2, 180 size + BASE_BUFFER_SIZE); 181 182 master = ByteBuffer.allocateDirect (newSize); 183 } 184 185 if (buffer == null) { 186 buffer = master.slice(); 187 } else { 188 int charsRemaining = AbstractLines.toCharIndex(buffer.capacity() - buffer.position()); 189 190 if (charsRemaining < size) { 191 buffer.flip(); 192 buffer = master.slice(); 193 } 194 } 195 outstandingBufferCount++; 196 return buffer; 197 } 198 199 203 public int write (ByteBuffer bb, boolean addNewLine) throws IOException { 204 synchronized (this) { 205 if (bb == buffer) { 206 buffer = null; 207 } 208 } 209 int position = size(); 210 int byteCount = bb.position(); 211 bb.flip(); 212 if (writeChannel().isOpen()) { writeChannel().write (bb); 214 if (addNewLine) { 215 writeChannel().write(ByteBuffer.wrap(OutWriter.lineSepBytes)); 216 } 217 synchronized (this) { 218 bytesWritten += byteCount + (addNewLine ? OutWriter.lineSepBytes.length : 0); 219 outstandingBufferCount--; 220 } 221 } 222 return position; 223 } 224 225 public synchronized void dispose() { 226 if (Controller.LOG) { 227 Controller.log ("Disposing file map storage"); 228 Controller.logStack(); 229 } 230 if (writeChannel != null && writeChannel.isOpen()) { 231 try { 232 writeChannel.close(); 233 writeChannel = null; 234 } catch (Exception e) { 235 Exceptions.printStackTrace(e); 236 } 237 } 238 if (readChannel != null && readChannel.isOpen()) { 239 try { 240 readChannel.close(); 241 readChannel = null; 242 } catch (Exception e) { 243 Exceptions.printStackTrace(e); 244 } 245 } 246 if (outfile != null && outfile.exists()) { 247 try { 248 outfile.delete(); 249 outfile = null; 250 } catch (Exception e) { 251 Exceptions.printStackTrace(e); 252 } 253 } 254 buffer = null; 255 contents = null; 256 } 257 258 263 public ByteBuffer getReadBuffer(int start, int byteCount) throws IOException { 264 ByteBuffer cont; 265 synchronized (this) { 266 cont = this.contents; 272 if (cont == null || start + byteCount > mappedRange || start < mappedStart) { 273 FileChannel ch = readChannel(); 274 long offset = start + byteCount; 275 mappedStart = Math.max((long)0, (long)(start - (MAX_MAP_RANGE /2))); 276 long prevMappedRange = mappedRange; 277 mappedRange = Math.min(ch.size(), start + (MAX_MAP_RANGE / 2)); 278 try { 279 try { 280 cont = ch.map(FileChannel.MapMode.READ_ONLY, 281 mappedStart, mappedRange - mappedStart); 282 this.contents = cont; 283 } catch (IOException ioe) { 284 Logger.getAnonymousLogger().info("Failed to memory map output file for " + "reading. Trying to read it normally."); Exceptions.printStackTrace(ioe); 287 288 cont = ByteBuffer.allocate((int) (mappedRange - mappedStart)); 292 ch.position(mappedStart).read(cont); 293 this.contents = cont; 294 } 295 } catch (IOException ioe) { 296 Logger.getAnonymousLogger().info("Failed to read output file. Start:" + start + " bytes reqd=" + byteCount + " mapped range=" + mappedRange + " previous mapped range=" + prevMappedRange + " channel size: " + ch.size()); throw ioe; 301 } 302 } 303 if (start - mappedStart > cont.limit() - byteCount) { 304 cont.position(Math.max(0, cont.limit() - byteCount)); 305 } else { 306 cont.position((int) (start - mappedStart)); 307 } 308 } 309 int limit = Math.min(cont.limit(), byteCount); 310 try { 311 return (ByteBuffer ) cont.slice().limit(limit); 312 } catch (Exception e) { 313 throw new IllegalStateException ("Error setting limit to " + limit + " contents size = " + cont.limit() + " requested: read " + "buffer from " + start + " to be " + byteCount + " bytes"); } 317 } 318 319 public synchronized int size() { 320 return bytesWritten; 321 } 322 323 public void flush() throws IOException { 324 if (buffer != null) { 325 if (Controller.LOG) Controller.log("FILEMAP STORAGE flush(): " + outstandingBufferCount); 326 write (buffer, false); 327 writeChannel.force(false); 328 buffer = null; 329 } 330 } 331 332 public void close() throws IOException { 333 if (writeChannel != null) { 334 flush(); 335 writeChannel.close(); 336 writeChannel = null; 337 if (Controller.LOG) Controller.log("FILEMAP STORAGE CLOSE. Outstanding buffer count: " + outstandingBufferCount); 338 } 339 } 340 341 public boolean isClosed() { 342 return writeChannel == null || !writeChannel.isOpen(); 343 } 344 } 345 | Popular Tags |