diff -r 00bb686fbe73 core.startup/src/org/netbeans/core/startup/layers/BinaryCacheManager.java --- a/core.startup/src/org/netbeans/core/startup/layers/BinaryCacheManager.java Thu Aug 11 00:28:59 2011 +0200 +++ b/core.startup/src/org/netbeans/core/startup/layers/BinaryCacheManager.java Thu Aug 11 16:56:26 2011 +0200 @@ -44,15 +44,24 @@ package org.netbeans.core.startup.layers; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URL; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.logging.Level; import org.openide.filesystems.FileSystem; import org.openide.filesystems.FileUtil; @@ -86,7 +95,7 @@ FileSystem fs = new BinaryFS(cacheLocation(), bb); return fs; } catch (BufferUnderflowException ex) { - throw (IOException)new IOException().initCause(ex); + throw new IOException(ex); } } @@ -95,6 +104,7 @@ return cacheLocation; } + @Override protected boolean openURLs() { return false; } @@ -103,10 +113,11 @@ protected void store(FileSystem fs, final MemFolder root, OutputStream os) throws IOException { try { sizes = new HashMap(1000); - int fsSize = computeSize(root); - LayerCacheManager.err.fine("Writing binary layer cache of length " + (fsSize + BinaryFS.MAGIC.length) + " to " + cacheLocation()); + Map strings = new HashMap(); + int fsSize = computeSize(root, strings); + LayerCacheManager.err.log(Level.FINE, "Writing binary layer cache of length {0} to {1}", new Object[]{fsSize + BinaryFS.MAGIC.length, cacheLocation()}); os.write(BinaryFS.MAGIC); - BinaryWriter bw = new BinaryWriter (os, root, fsSize); + BinaryWriter bw = new BinaryWriter (os, root, fsSize, strings); writeFolder(bw, root, true); } finally { sizes = null; // free the cache @@ -135,7 +146,7 @@ int baseOffset = bw.getPosition(); for (Iterator it = folder.children.iterator(); it.hasNext(); ) { MemFileOrFolder item = (MemFileOrFolder)it.next(); - baseOffset += computeHeaderSize(item); + baseOffset += computeHeaderSize(item, null); } // baseOffset now contains the offset of the first file content @@ -146,7 +157,7 @@ bw.writeByte((item instanceof MemFile) ? (byte)0 : (byte)1); //boolean isFolder bw.writeInt(baseOffset); // int contentRef - baseOffset += computeSize(item); + baseOffset += computeSize(item, null); // baseOffset now contains the offset of the next file content } @@ -236,7 +247,7 @@ // this map is actually valid only during BFS regeneration, null otherwise private HashMap sizes; - private int computeSize(MemFileOrFolder mf) { + private int computeSize(MemFileOrFolder mf, Map text) { Integer i = sizes.get(mf); if (i != null) return i; @@ -246,7 +257,7 @@ size += 4; // int attrCount if (mf.attrs != null) { for (Iterator it = mf.attrs.iterator(); it.hasNext(); ) { - size += computeSize((MemAttr)it.next()); // Attribute[attrCount] attrs + size += computeSize((MemAttr)it.next(), text); // Attribute[attrCount] attrs } } @@ -254,7 +265,7 @@ MemFile file = (MemFile)mf; size += 4; // int contentLength if (file.ref != null) { - size += computeSize(file.ref.toString()); // String uri + size += computeSize(file.ref.toString(), text); // String uri } else if (file.contents != null) { size += file.contents.length; } // else size += 0; // no content, no uri @@ -263,8 +274,8 @@ size += 4; // int fileCount if (folder.children != null) { for (MemFileOrFolder item : folder.children) { - size += computeHeaderSize(item); // File[fileCount] references - size += computeSize(item); // File/FolderContent[fileCount] contents + size += computeHeaderSize(item, text); // File[fileCount] references + size += computeSize(item, text); // File/FolderContent[fileCount] contents } } } @@ -272,31 +283,38 @@ return size; } - private int computeHeaderSize(MemFileOrFolder mof) { + private int computeHeaderSize(MemFileOrFolder mof, Map text) { // String name, boolean isFolder, int contentRef - return computeSize(mof.name) + 1 + 4; + return computeSize(mof.name, text) + 1 + 4; } - private static int computeSize(String s) { // int len, byte[len] utf8 - try { - return 4 + s.getBytes("UTF-8").length; // NOI18N - } catch (UnsupportedEncodingException e) { - throw (IllegalStateException) new IllegalStateException(e.toString()).initCause(e); + private static int computeSize(String s, Map text) { // int len, byte[len] utf8 + if (text != null) { + int[] count = text.get(s); + if (count == null) { + count = new int[1]; + text.put(s, count); + } + count[0]++; } + return 4; } - private int computeSize(MemAttr attr) { //String name, byte type, String value - return computeSize(attr.name) + 1 + computeSize(attr.data); + private int computeSize(MemAttr attr, Map text) { //String name, byte type, String value + return computeSize(attr.name, text) + 1 + computeSize(attr.data, text); } private static final class BinaryWriter { private OutputStream os; private int position; /** map from base URL to int[1] value */ - private java.util.Map urls; - BinaryWriter(OutputStream os, MemFolder root, int fsSize) throws IOException { + private final Map urls; + private final Map strings; + BinaryWriter(OutputStream os, MemFolder root, int fsSize, Map strings) throws IOException { this.os = os; - urls = writeBaseUrls (root, fsSize); + HashMap map = new HashMap(); + this.strings = Collections.unmodifiableMap(map); + urls = writeBaseUrls (root, fsSize, strings, map); position = 0; } @@ -324,15 +342,9 @@ } void writeString(String str) throws IOException { - byte[] data; - try { - data = str.getBytes("UTF-8"); // NOI18N - } catch (UnsupportedEncodingException e) { - throw (IllegalStateException) new IllegalStateException(e.toString()).initCause(e); - } - - writeInt(data.length); - writeBytes(data); + Integer offset = strings.get(str); + assert offset != null : "Found " + str; + writeInt(offset); } void writeBaseURL (java.net.URL url) throws IOException { @@ -348,7 +360,9 @@ writeInt (index); } - private java.util.Map writeBaseUrls (MemFileOrFolder root, int fsSize) throws IOException { + private java.util.Map writeBaseUrls( + MemFileOrFolder root, int fsSize, Map texts, Map fillIn + ) throws IOException { java.util.LinkedHashMap map = new java.util.LinkedHashMap (); int[] counter = new int[1]; @@ -362,10 +376,23 @@ assert ((int[])entry.getValue ())[0] == i : i + "th key should be it " + ((int[])entry.getValue ())[0]; - size += computeSize (u.toExternalForm ()); + size += computeSize (u.toExternalForm (), texts); } - writeInt(BinaryFS.MAGIC.length + 4 + 4 + size + fsSize); // size of the whole image + ByteArrayOutputStream arr = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(arr); + for (String txt : sort(texts.entrySet())) { + fillIn.put(txt, dos.size()); + dos.writeUTF(txt); + } + dos.flush(); + + int textSize = dos.size(); + writeInt(BinaryFS.MAGIC.length + 4 + 4 + textSize + 4 + size + fsSize); // size of the whole image + + writeInt(textSize); + os.write(arr.toByteArray()); + writeInt (size); // the size of urls part it = map.entrySet ().iterator (); @@ -394,5 +421,22 @@ } } } + + private List sort(Set> entrySet) { + List> lst = new ArrayList>(entrySet); + class C implements Comparator> { + @Override + public int compare(Entry o1, Entry o2) { + return o2.getValue()[0] - o1.getValue()[0]; + } + } + Collections.sort(lst, new C()); + List res = new ArrayList(); + for (Entry entry : lst) { + res.add(entry.getKey()); + } + return res; + + } } } diff -r 00bb686fbe73 core.startup/src/org/netbeans/core/startup/layers/BinaryFS.java --- a/core.startup/src/org/netbeans/core/startup/layers/BinaryFS.java Thu Aug 11 00:28:59 2011 +0200 +++ b/core.startup/src/org/netbeans/core/startup/layers/BinaryFS.java Thu Aug 11 16:56:26 2011 +0200 @@ -46,6 +46,8 @@ import java.beans.PropertyVetoException; import java.io.ByteArrayInputStream; +import java.io.DataInput; +import java.io.DataInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -93,7 +95,7 @@ * * @author Petr Nejedly */ -final class BinaryFS extends FileSystem { +final class BinaryFS extends FileSystem implements DataInput { static final Logger LOG = Logger.getLogger(BinaryFS.class.getName()); /* Format: * MAGIC @@ -103,7 +105,7 @@ * FS data */ - static final byte[] MAGIC = "org.netbeans.core.projects.cache.BinaryV5".getBytes(); // NOI18N + static final byte[] MAGIC = "org.netbeans.core.projects.cache.BinaryV6".getBytes(); // NOI18N /** An empty array of SystemActions. */ static final SystemAction[] NO_ACTIONS = new SystemAction[0]; @@ -121,6 +123,8 @@ private final List urls; private final List modifications; private final Date lastModified = new Date(); + private final Map texts; + private final ByteBuffer strings; @SuppressWarnings("deprecation") private void _setSystemName(String s) throws PropertyVetoException { @@ -132,10 +136,10 @@ try { _setSystemName("BinaryFS" + binaryFile.replace('/', '-').replace(File.separatorChar, '-')); // NOI18N } catch (PropertyVetoException ex) { - throw (IOException)new IOException().initCause(ex); + throw new IOException(ex); } - LayerCacheManager.err.fine("Reading " + binaryFile + " buffer: " + buff.limit()); + LayerCacheManager.err.log(Level.FINE, "Reading {0} buffer: {1}", new Object[]{binaryFile, buff.limit()}); this.binaryFile = binaryFile; @@ -151,9 +155,13 @@ } LayerCacheManager.err.log(Level.FINER, "Stored Len OK: {0}", storedLen); + int strLen = buff.getInt(); + this.texts = new HashMap(); + this.strings = buff.slice().asReadOnlyBuffer(); + buff.position(buff.position() + strLen); // fill the modifications array - int stop = buff.getInt() + 8 + MAGIC.length; + int stop = buff.getInt() + 8 + MAGIC.length + strLen + 4; urls = new ArrayList(); List _modifications = new ArrayList(); while (buff.position() < stop) { @@ -176,6 +184,7 @@ * null if no such file exists * */ + @Override public FileObject findResource(String name) { if (name.length () == 0) { return root; @@ -239,11 +248,104 @@ return true; } - static String getString(ByteBuffer buffer) throws IOException { - int len = buffer.getInt(); - byte[] arr = new byte[len]; - buffer.get(arr); - return new String(arr, "UTF-8"); //.intern(); + final String getString(final ByteBuffer buffer) throws IOException { + synchronized (strings) { + int offset = buffer.getInt(); + String t = texts.get(offset); + if (t != null) { + return t; + } + strings.position(offset); + String s = DataInputStream.readUTF(this); + texts.put(offset, s); + return s; + } + } + + @Override + public void readFully(byte[] b, int off, int len) throws IOException { + Thread.holdsLock(strings); + strings.get(b, off, len); + } + + @Override + public int readUnsignedShort() throws IOException { + Thread.holdsLock(strings); + int ch1 = strings.get(); + if (ch1 < 0) { + ch1 += 256; + } + int ch2 = strings.get(); + if (ch2 < 0) { + ch2 += 256; + } + return (ch1 << 8) + ch2; + } + + @Override + public void readFully(byte[] b) throws IOException { + throw new IOException(); + } + + @Override + public int skipBytes(int n) throws IOException { + throw new IOException(); + } + + @Override + public boolean readBoolean() throws IOException { + throw new IOException(); + } + + @Override + public byte readByte() throws IOException { + throw new IOException(); + } + + @Override + public int readUnsignedByte() throws IOException { + throw new IOException(); + } + + @Override + public short readShort() throws IOException { + throw new IOException(); + } + + + @Override + public char readChar() throws IOException { + throw new IOException(); + } + + @Override + public int readInt() throws IOException { + throw new IOException(); + } + + @Override + public long readLong() throws IOException { + throw new IOException(); + } + + @Override + public float readFloat() throws IOException { + throw new IOException(); + } + + @Override + public double readDouble() throws IOException { + throw new IOException(); + } + + @Override + public String readLine() throws IOException { + throw new IOException(); + } + + @Override + public String readUTF() throws IOException { + throw new IOException(); } @@ -449,13 +551,13 @@ if (attrCount > 0) attrs = new HashMap(attrCount*4/3+1); for (int i=0; i< attrCount; i++) { // do read attribute - // attribute names are highly duplicated, intern! - String attrName = getString(sub).intern(); // String attrName + // attribute names are highly duplicated! + String attrName = getString(sub); // String attrName byte type = sub.get(); // byte attrType // values have high redundancy as well, // like "true", "JSeparator", paths to orig files from // shadow, ... - String value = getString(sub).intern(); // String attrValue + String value = getString(sub); // String attrValue attrs.put(attrName, new AttrImpl(type, value)); }