diff options
author | Thomas Watson | 2016-02-25 15:09:00 +0000 |
---|---|---|
committer | Thomas Watson | 2016-02-25 22:03:25 +0000 |
commit | 61f06f085ec22f9322b1a74c755c331f82041d69 (patch) | |
tree | 11aa42d94baca7b939c32d962fff3057d3c18693 /bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java | |
parent | bc100ec508c1afd07a94f16104872c29503446f9 (diff) | |
download | rt.equinox.framework-61f06f085ec22f9322b1a74c755c331f82041d69.tar.gz rt.equinox.framework-61f06f085ec22f9322b1a74c755c331f82041d69.tar.xz rt.equinox.framework-61f06f085ec22f9322b1a74c755c331f82041d69.zip |
Bug 488501 - optimize storage and reading of strings and versions
Change-Id: I4dcbe3fe97a85597812d6c507a38a535a754e77d
Signed-off-by: Thomas Watson <tjwatson@us.ibm.com>
Diffstat (limited to 'bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java')
-rw-r--r-- | bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java | 341 |
1 files changed, 207 insertions, 134 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java index 2f2cba462..d0f66bc22 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/container/ModuleDatabase.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2014 IBM Corporation and others. + * Copyright (c) 2012, 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,8 +11,6 @@ package org.eclipse.osgi.container; import java.io.*; -import java.net.URI; -import java.net.URISyntaxException; import java.util.*; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -929,17 +927,18 @@ public class ModuleDatabase { private static final int VERSION = 2; private static final byte NULL = 0; private static final byte OBJECT = 1; + private static final byte INDEX = 2; private static final byte LONG_STRING = 3; private static final String UTF_8 = "UTF-8"; //$NON-NLS-1$ private static final byte VALUE_STRING = 0; - private static final byte VALUE_STRING_ARRAY = 1; - private static final byte VAlUE_BOOLEAN = 2; - private static final byte VALUE_INTEGER = 3; + // REMOVED treated as List<String> - private static final byte VALUE_STRING_ARRAY = 1; + // REMOVED never was really supported by the OSGi builder - private static final byte VAlUE_BOOLEAN = 2; + // REMOVED never was really supported by the OSGi builder - private static final byte VALUE_INTEGER = 3; private static final byte VALUE_LONG = 4; private static final byte VALUE_DOUBLE = 5; private static final byte VALUE_VERSION = 6; - private static final byte VALUE_URI = 7; + // REMOVED treated as type String - private static final byte VALUE_URI = 7; private static final byte VALUE_LIST = 8; private static int addToWriteTable(Object object, Map<Object, Integer> objectTable) { @@ -964,19 +963,47 @@ public class ModuleDatabase { out.writeLong(moduleDatabase.getNextId()); out.writeInt(moduleDatabase.getInitialModuleStartLevel()); - List<Module> modules = moduleDatabase.getModules(); - Map<Object, Integer> objectTable = new HashMap<Object, Integer>(); - // prime the object table with all the maps + // prime the object table with all the strings, versions and maps + Set<String> allStrings = new HashSet<String>(); + Set<Version> allVersions = new HashSet<Version>(); Set<Map<String, ?>> allMaps = new HashSet<Map<String, ?>>(); + + // first gather all the strings, versions and maps from the modules + List<Module> modules = moduleDatabase.getModules(); for (Module module : modules) { - getMaps(module, allMaps); + getStringsVersionsAndMaps(module, moduleDatabase, allStrings, allVersions, allMaps); } + // outside of the modules the wirings have 'substituted' packages strings + Map<ModuleRevision, ModuleWiring> wirings = moduleDatabase.wirings; + for (ModuleWiring wiring : wirings.values()) { + Collection<String> substituted = wiring.getSubstitutedNames(); + for (String pkgName : substituted) { + allStrings.add(pkgName); + } + } + + // Now persist all the Strings + Map<Object, Integer> objectTable = new HashMap<Object, Integer>(); + allStrings.remove(null); + out.writeInt(allStrings.size()); + for (String string : allStrings) { + writeString(string, out, objectTable); + out.writeInt(addToWriteTable(string, objectTable)); + } + // Followed by versions which may reference strings with their qualifier + out.writeInt(allVersions.size()); + for (Version version : allVersions) { + writeVersion(version, out, objectTable); + out.writeInt(addToWriteTable(version, objectTable)); + } + // Followed by maps which may reference the strings and versions out.writeInt(allMaps.size()); for (Map<String, ?> map : allMaps) { + writeMap(map, out, objectTable); out.writeInt(addToWriteTable(map, objectTable)); - writeMap(map, out); } - // prime the object table with all modules + + // Followed by modules which reference the strings, versions, and maps out.writeInt(modules.size()); for (Module module : modules) { writeModule(module, moduleDatabase, out, objectTable); @@ -990,8 +1017,7 @@ public class ModuleDatabase { return; } - Map<ModuleRevision, ModuleWiring> wirings = moduleDatabase.wirings; - // prime the object table with all the required wires + // prime the object table with all the required wires which reference the modules out.writeInt(wirings.size()); for (ModuleWiring wiring : wirings.values()) { List<ModuleWire> requiredWires = wiring.getPersistentRequiredWires(); @@ -1001,7 +1027,7 @@ public class ModuleDatabase { } } - // now write all the info about each wiring using only indexes + // now write all the info about each wiring using only indexes from the objectTable for (ModuleWiring wiring : wirings.values()) { writeWiring(wiring, out, objectTable); } @@ -1009,21 +1035,65 @@ public class ModuleDatabase { out.flush(); } - private static void getMaps(Module module, Set<Map<String, ?>> allMaps) { + private static void getStringsVersionsAndMaps(Module module, ModuleDatabase moduleDatabase, Set<String> allStrings, Set<Version> allVersions, Set<Map<String, ?>> allMaps) { ModuleRevision current = module.getCurrentRevision(); if (current == null) return; + allStrings.add(module.getLocation()); + allStrings.add(current.getSymbolicName()); + allStrings.add(current.getVersion().getQualifier()); + allVersions.add(current.getVersion()); + EnumSet<Settings> settings = moduleDatabase.moduleSettings.get(module.getId()); + if (settings != null) { + for (Settings setting : settings) { + allStrings.add(setting.toString()); + } + } + List<ModuleCapability> capabilities = current.getModuleCapabilities(null); for (ModuleCapability capability : capabilities) { - allMaps.add(capability.getPersistentAttributes()); - allMaps.add(capability.getDirectives()); + allStrings.add(capability.getNamespace()); + addMap(capability.getPersistentAttributes(), allStrings, allVersions, allMaps); + addMap(capability.getDirectives(), allStrings, allVersions, allMaps); } List<ModuleRequirement> requirements = current.getModuleRequirements(null); for (ModuleRequirement requirement : requirements) { - allMaps.add(requirement.getAttributes()); - allMaps.add(requirement.getDirectives()); + allStrings.add(requirement.getNamespace()); + addMap(requirement.getAttributes(), allStrings, allVersions, allMaps); + addMap(requirement.getDirectives(), allStrings, allVersions, allMaps); + } + } + + private static void addMap(Map<String, ?> map, Set<String> allStrings, Set<Version> allVersions, Set<Map<String, ?>> allMaps) { + if (!allMaps.add(map)) { + // map was already added + return; + } + for (Map.Entry<String, ?> entry : map.entrySet()) { + allStrings.add(entry.getKey()); + Object value = entry.getValue(); + if (value instanceof String) { + allStrings.add((String) value); + } else if (value instanceof Version) { + allStrings.add(((Version) value).getQualifier()); + allVersions.add((Version) value); + } else if (value instanceof List) { + switch (getListType((List<?>) value)) { + case VALUE_STRING : + for (Object string : (List<?>) value) { + allStrings.add((String) string); + } + break; + case VALUE_VERSION : + for (Object version : (List<?>) value) { + allStrings.add(((Version) version).getQualifier()); + allVersions.add((Version) version); + } + break; + } + } } } @@ -1038,9 +1108,17 @@ public class ModuleDatabase { Map<Integer, Object> objectTable = new HashMap<Integer, Object>(); if (version >= 2) { + int numStrings = in.readInt(); + for (int i = 0; i < numStrings; i++) { + readIndexedString(in, objectTable); + } + int numVersions = in.readInt(); + for (int i = 0; i < numVersions; i++) { + readIndexedVersion(in, objectTable); + } int numMaps = in.readInt(); for (int i = 0; i < numMaps; i++) { - readMap(in, objectTable); + readIndexedMap(in, objectTable); } } int numModules = in.readInt(); @@ -1087,11 +1165,11 @@ public class ModuleDatabase { return; out.writeInt(addToWriteTable(current, objectTable)); - writeString(module.getLocation(), out); + writeString(module.getLocation(), out, objectTable); out.writeLong(module.getId()); - writeString(current.getSymbolicName(), out); - writeVersion(current.getVersion(), out); + writeString(current.getSymbolicName(), out, objectTable); + writeVersion(current.getVersion(), out, objectTable); out.writeInt(current.getTypes()); List<ModuleCapability> capabilities = current.getModuleCapabilities(null); @@ -1113,7 +1191,7 @@ public class ModuleDatabase { out.writeInt(settings == null ? 0 : settings.size()); if (settings != null) { for (Settings setting : settings) { - writeString(setting.name(), out); + writeString(setting.name(), out, objectTable); } } @@ -1127,10 +1205,10 @@ public class ModuleDatabase { private static void readModule(ModuleDatabase moduleDatabase, DataInputStream in, Map<Integer, Object> objectTable, int version) throws IOException { ModuleRevisionBuilder builder = new ModuleRevisionBuilder(); int moduleIndex = in.readInt(); - String location = readString(in); + String location = readString(in, objectTable); long id = in.readLong(); - builder.setSymbolicName(readString(in)); - builder.setVersion(readVersion(in)); + builder.setSymbolicName(readString(in, objectTable)); + builder.setVersion(readVersion(in, objectTable)); builder.setTypes(in.readInt()); int numCapabilities = in.readInt(); @@ -1153,7 +1231,7 @@ public class ModuleDatabase { if (numSettings > 0) { settings = EnumSet.noneOf(Settings.class); for (int i = 0; i < numSettings; i++) { - settings.add(Settings.valueOf(readString(in))); + settings.add(Settings.valueOf(readString(in, objectTable))); } } @@ -1258,7 +1336,7 @@ public class ModuleDatabase { Collection<String> substituted = wiring.getSubstitutedNames(); out.writeInt(substituted.size()); for (String pkgName : substituted) { - writeString(pkgName, out); + writeString(pkgName, out, objectTable); } } @@ -1294,14 +1372,14 @@ public class ModuleDatabase { int numSubstitutedNames = in.readInt(); Collection<String> substituted = new ArrayList<String>(numSubstitutedNames); for (int i = 0; i < numSubstitutedNames; i++) { - substituted.add(readString(in)); + substituted.add(readString(in, objectTable)); } return new ModuleWiring(revision, capabilities, requirements, providedWires, requiredWires, substituted); } private static void writeGenericInfo(String namespace, Map<String, ?> attributes, Map<String, String> directives, DataOutputStream out, Map<Object, Integer> objectTable) throws IOException { - writeString(namespace, out); + writeString(namespace, out, objectTable); Integer attributesIndex = objectTable.get(attributes); Integer directivesIndex = objectTable.get(directives); @@ -1313,9 +1391,9 @@ public class ModuleDatabase { @SuppressWarnings("unchecked") private static void readGenericInfo(boolean isCapability, DataInputStream in, ModuleRevisionBuilder builder, Map<Integer, Object> objectTable, int version) throws IOException { - String namespace = readString(in); - Map<String, Object> attributes = version >= 2 ? (Map<String, Object>) objectTable.get(in.readInt()) : readMap(in); - Map<String, ?> directives = version >= 2 ? (Map<String, ?>) objectTable.get(in.readInt()) : readMap(in); + String namespace = readString(in, objectTable); + Map<String, Object> attributes = version >= 2 ? (Map<String, Object>) objectTable.get(in.readInt()) : readMap(in, objectTable); + Map<String, ?> directives = version >= 2 ? (Map<String, ?>) objectTable.get(in.readInt()) : readMap(in, objectTable); if (attributes == null || directives == null) throw new NullPointerException("Could not find the expected indexes"); //$NON-NLS-1$ if (isCapability) { @@ -1326,7 +1404,7 @@ public class ModuleDatabase { } - private static void writeMap(Map<String, ?> source, DataOutputStream out) throws IOException { + private static void writeMap(Map<String, ?> source, DataOutputStream out, Map<Object, Integer> objectTable) throws IOException { if (source == null) { out.writeInt(0); } else { @@ -1335,19 +1413,10 @@ public class ModuleDatabase { while (iter.hasNext()) { String key = iter.next(); Object value = source.get(key); - writeString(key, out); + writeString(key, out, objectTable); if (value instanceof String) { out.writeByte(VALUE_STRING); - writeString((String) value, out); - } else if (value instanceof String[]) { - out.writeByte(VALUE_STRING_ARRAY); - writeStringArray(out, (String[]) value); - } else if (value instanceof Boolean) { - out.writeByte(VAlUE_BOOLEAN); - out.writeBoolean(((Boolean) value).booleanValue()); - } else if (value instanceof Integer) { - out.writeByte(VALUE_INTEGER); - out.writeInt(((Integer) value).intValue()); + writeString((String) value, out, objectTable); } else if (value instanceof Long) { out.writeByte(VALUE_LONG); out.writeLong(((Long) value).longValue()); @@ -1356,40 +1425,41 @@ public class ModuleDatabase { out.writeDouble(((Double) value).doubleValue()); } else if (value instanceof Version) { out.writeByte(VALUE_VERSION); - writeVersion((Version) value, out); - } else if (value instanceof URI) { - out.writeByte(VALUE_URI); - writeString(value.toString(), out); + writeVersion((Version) value, out, objectTable); } else if (value instanceof List) { out.writeByte(VALUE_LIST); - writeList(out, (List<?>) value); + writeList(out, (List<?>) value, objectTable); + } else { + // better do our best and write a string + // probably should warn here + out.writeByte(VALUE_STRING); + writeString((String) value, out, objectTable); } } } } - private static void readMap(DataInputStream in, Map<Integer, Object> objectTable) throws IOException { - int mapIndex = in.readInt(); - Map<String, Object> result = readMap(in); - addToReadTable(result, mapIndex, objectTable); + private static void readIndexedMap(DataInputStream in, Map<Integer, Object> objectTable) throws IOException { + Map<String, Object> result = readMap(in, objectTable); + addToReadTable(result, in.readInt(), objectTable); } - private static Map<String, Object> readMap(DataInputStream in) throws IOException { + private static Map<String, Object> readMap(DataInputStream in, Map<Integer, Object> objectTable) throws IOException { int count = in.readInt(); Map<String, Object> result; if (count == 0) { result = Collections.emptyMap(); } else if (count == 1) { - String key = readString(in); + String key = readString(in, objectTable); byte type = in.readByte(); - Object value = readMapValue(in, type); + Object value = readMapValue(in, type, objectTable); result = Collections.singletonMap(key, value); } else { result = new HashMap<String, Object>(count); for (int i = 0; i < count; i++) { - String key = readString(in); + String key = readString(in, objectTable); byte type = in.readByte(); - Object value = readMapValue(in, type); + Object value = readMapValue(in, type, objectTable); result.put(key, value); } result = Collections.unmodifiableMap(result); @@ -1397,57 +1467,24 @@ public class ModuleDatabase { return result; } - private static Object readMapValue(DataInputStream in, int type) throws IOException { + private static Object readMapValue(DataInputStream in, int type, Map<Integer, Object> objectTable) throws IOException { switch (type) { case VALUE_STRING : - return readString(in); - case VALUE_STRING_ARRAY : - return readStringArray(in); - case VAlUE_BOOLEAN : - return in.readBoolean() ? Boolean.TRUE : Boolean.FALSE; - case VALUE_INTEGER : - return new Integer(in.readInt()); + return readString(in, objectTable); case VALUE_LONG : return new Long(in.readLong()); case VALUE_DOUBLE : return new Double(in.readDouble()); case VALUE_VERSION : - return readVersion(in); - case VALUE_URI : - try { - return new URI(readString(in)); - } catch (URISyntaxException e) { - return null; - } + return readVersion(in, objectTable); case VALUE_LIST : - return readList(in); + return readList(in, objectTable); default : - throw new IOException("Invalid type: " + type); //$NON-NLS-1$ + throw new IllegalArgumentException("Invalid type: " + type); //$NON-NLS-1$ } } - private static void writeStringArray(DataOutputStream out, String[] value) throws IOException { - if (value == null) { - out.writeInt(0); - } else { - out.writeInt(value.length); - for (int i = 0; i < value.length; i++) - writeString(value[i], out); - } - - } - - private static String[] readStringArray(DataInputStream in) throws IOException { - int count = in.readInt(); - if (count == 0) - return null; - String[] result = new String[count]; - for (int i = 0; i < count; i++) - result[i] = readString(in); - return result; - } - - private static void writeList(DataOutputStream out, List<?> list) throws IOException { + private static void writeList(DataOutputStream out, List<?> list, Map<Object, Integer> objectTable) throws IOException { if (list.isEmpty()) { out.writeInt(0); return; @@ -1462,10 +1499,7 @@ public class ModuleDatabase { for (Object value : list) { switch (type) { case VALUE_STRING : - writeString((String) value, out); - break; - case VALUE_INTEGER : - out.writeInt(((Integer) value).intValue()); + writeString((String) value, out, objectTable); break; case VALUE_LONG : out.writeLong(((Long) value).longValue()); @@ -1474,7 +1508,7 @@ public class ModuleDatabase { out.writeDouble(((Double) value).doubleValue()); break; case VALUE_VERSION : - writeVersion((Version) value, out); + writeVersion((Version) value, out, objectTable); break; default : break; @@ -1488,8 +1522,6 @@ public class ModuleDatabase { Object type = list.get(0); if (type instanceof String) return VALUE_STRING; - if (type instanceof Integer) - return VALUE_INTEGER; if (type instanceof Long) return VALUE_LONG; if (type instanceof Double) @@ -1499,68 +1531,94 @@ public class ModuleDatabase { return -2; } - private static List<?> readList(DataInputStream in) throws IOException { + private static List<?> readList(DataInputStream in, Map<Integer, Object> objectTable) throws IOException { int size = in.readInt(); if (size == 0) return Collections.emptyList(); byte listType = in.readByte(); if (size == 1) { - return Collections.singletonList(readListValue(listType, in)); + return Collections.singletonList(readListValue(listType, in, objectTable)); } List<Object> list = new ArrayList<Object>(size); for (int i = 0; i < size; i++) { - list.add(readListValue(listType, in)); + list.add(readListValue(listType, in, objectTable)); } return Collections.unmodifiableList(list); } - private static Object readListValue(byte listType, DataInputStream in) throws IOException { + private static Object readListValue(byte listType, DataInputStream in, Map<Integer, Object> objectTable) throws IOException { switch (listType) { case VALUE_STRING : - return readString(in); - case VALUE_INTEGER : - return new Integer(in.readInt()); + return readString(in, objectTable); case VALUE_LONG : return new Long(in.readLong()); case VALUE_DOUBLE : return new Double(in.readDouble()); case VALUE_VERSION : - return readVersion(in); + return readVersion(in, objectTable); default : - throw new IOException("Invalid type: " + listType); //$NON-NLS-1$ + throw new IllegalArgumentException("Invalid type: " + listType); //$NON-NLS-1$ } } - private static void writeVersion(Version version, DataOutputStream out) throws IOException { + private static void writeVersion(Version version, DataOutputStream out, Map<Object, Integer> objectTable) throws IOException { if (version == null || version.equals(Version.emptyVersion)) { out.writeByte(NULL); return; } + Integer index = objectTable.get(version); + if (index != null) { + out.writeByte(INDEX); + out.writeInt(index); + return; + } out.writeByte(OBJECT); out.writeInt(version.getMajor()); out.writeInt(version.getMinor()); out.writeInt(version.getMicro()); - writeQualifier(version.getQualifier(), out); + writeQualifier(version.getQualifier(), out, objectTable); } - private static void writeQualifier(String string, DataOutputStream out) throws IOException { + private static void writeQualifier(String string, DataOutputStream out, Map<Object, Integer> objectTable) throws IOException { if (string != null && string.length() == 0) string = null; - writeString(string, out); + writeString(string, out, objectTable); + } + + private static Version readIndexedVersion(DataInputStream in, Map<Integer, Object> objectTable) throws IOException { + Version version = readVersion0(in, objectTable, false); + addToReadTable(version, in.readInt(), objectTable); + return version; + } + + private static Version readVersion(DataInputStream in, Map<Integer, Object> objectTable) throws IOException { + return readVersion0(in, objectTable, true); } - private static Version readVersion(DataInputStream in) throws IOException { - byte tag = in.readByte(); - if (tag == NULL) + private static Version readVersion0(DataInputStream in, Map<Integer, Object> objectTable, boolean intern) throws IOException { + byte type = in.readByte(); + if (type == INDEX) { + int index = in.readInt(); + return (Version) objectTable.get(index); + } + if (type == NULL) return Version.emptyVersion; int majorComponent = in.readInt(); int minorComponent = in.readInt(); int serviceComponent = in.readInt(); - String qualifierComponent = readString(in); - return ObjectPool.intern(new Version(majorComponent, minorComponent, serviceComponent, qualifierComponent)); + String qualifierComponent = readString(in, objectTable); + Version version = new Version(majorComponent, minorComponent, serviceComponent, qualifierComponent); + return intern ? ObjectPool.intern(version) : version; } - private static void writeString(String string, DataOutputStream out) throws IOException { + private static void writeString(String string, DataOutputStream out, Map<Object, Integer> objectTable) throws IOException { + Integer index = string != null ? objectTable.get(string) : null; + if (index != null) { + out.writeByte(INDEX); + out.writeInt(index); + return; + } + if (string == null) out.writeByte(NULL); else { @@ -1577,21 +1635,36 @@ public class ModuleDatabase { } } - static private String readString(DataInputStream in) throws IOException { + static private String readIndexedString(DataInputStream in, Map<Integer, Object> objectTable) throws IOException { + String string = readString0(in, objectTable, false); + addToReadTable(string, in.readInt(), objectTable); + return string; + } + + static private String readString(DataInputStream in, Map<Integer, Object> objectTable) throws IOException { + return readString0(in, objectTable, true); + } + + static private String readString0(DataInputStream in, Map<Integer, Object> objectTable, boolean intern) throws IOException { byte type = in.readByte(); - if (type == NULL) + if (type == INDEX) { + int index = in.readInt(); + return (String) objectTable.get(index); + } + if (type == NULL) { return null; - + } + String string; if (type == LONG_STRING) { int length = in.readInt(); byte[] data = new byte[length]; in.readFully(data); - String string = new String(data, UTF_8); - - return ObjectPool.intern(string); + string = new String(data, UTF_8); + } else { + string = in.readUTF(); } - return ObjectPool.intern(in.readUTF()); + return intern ? ObjectPool.intern(string) : string; } } } |