diff options
| author | Andrew Haley <aph@redhat.com> | 2016-09-30 16:24:48 +0000 |
|---|---|---|
| committer | Andrew Haley <aph@gcc.gnu.org> | 2016-09-30 16:24:48 +0000 |
| commit | 07b78716af6a9d7c9fd1e94d9baf94a52c873947 (patch) | |
| tree | 3f22b3241c513ad168c8353805614ae1249410f4 /libjava/gnu/gcj/runtime/PersistentByteMap.java | |
| parent | eae993948bae8b788c53772bcb9217c063716f93 (diff) | |
Makefile.def: Remove libjava.
2016-09-30 Andrew Haley <aph@redhat.com>
* Makefile.def: Remove libjava.
* Makefile.tpl: Likewise.
* Makefile.in: Regenerate.
* configure.ac: Likewise.
* configure: Likewise.
* gcc/java: Remove.
* libjava: Likewise.
From-SVN: r240662
Diffstat (limited to 'libjava/gnu/gcj/runtime/PersistentByteMap.java')
| -rw-r--r-- | libjava/gnu/gcj/runtime/PersistentByteMap.java | 619 |
1 files changed, 0 insertions, 619 deletions
diff --git a/libjava/gnu/gcj/runtime/PersistentByteMap.java b/libjava/gnu/gcj/runtime/PersistentByteMap.java deleted file mode 100644 index fec30806f81..00000000000 --- a/libjava/gnu/gcj/runtime/PersistentByteMap.java +++ /dev/null @@ -1,619 +0,0 @@ -/* Copyright (C) 2004, 2005 Free Software Foundation - - This file is part of libgcj. - -This software is copyrighted work licensed under the terms of the -Libgcj License. Please consult the file "LIBGCJ_LICENSE" for -details. */ - - - -/* A PersistentByteMap maps a byte array to another byte array. It -uses a file that does not need to be serialized but may be -memory-mapped and read in-place. So, even if there are many instances -of gcj applications running, they can share PersistentByteMaps. - -The idea is to make searches as fast as possible: opening a -PersistentByteMap is cheap and search time doesn't grow with the -number of entries in the table. On the other hand, enumerating the -map is slow, but that is a relatively uncommon operation. - -The main use of this class is to provide a way to map the -MessageDigest of a class file to the location of a DSO that contains -the compiled version of that class. It is up the the installer of an -application to keep the DSO up to date with the jar. - -USAGE: - MessageDigest md = MessageDigest.getInstance("MD5"); - digest = md.digest(bytes); - - PersistentByteMap map - = new PersistentByteMap - (fileName, PersistentByteMap.AccessMode.READ_ONLY); - - byte[] soName = map.get(digest); - if (soName) - { - String SharedLibraryName = new String(soName); - -BUGS/FEATURES: - remove() isn't written yet. - - capacity is fixed once the map has been created. - - We use linear probing to resolve collisions. It might be - better to use a scheme that results in fewer probes to - determine that an item isn't found. However, even when the - table is half full there are only on average 1.5 probes for a - successful search and 2.5 probes for an unsuccessful one. - - We don't do any locking at all: adding to a PersistentByteMap - at runtime is possible, but it requires filesystem locks - around get(), put(), and remove(). -*/ - -package gnu.gcj.runtime; - -import java.io.*; -import java.nio.*; -import java.nio.channels.*; -import java.util.*; -import java.security.MessageDigest; -import java.math.BigInteger; - -public class PersistentByteMap -{ - private MappedByteBuffer buf; - - static private final int MAGIC = 0; - static private final int VERSION = 4; - static private final int CAPACITY = 8; - static private final int TABLE_BASE = 12; - static private final int STRING_BASE = 16; - static private final int STRING_SIZE = 20; - static private final int FILE_SIZE = 24; - static private final int ELEMENTS = 28; - - static private final int INT_SIZE = 4; - - static private final int TABLE_ENTRY_SIZE = 2 * INT_SIZE; - - private int capacity; // number of entries - private int table_base; // offset from start of file, in bytes - private int string_base; // offset from start of file, in bytes - private int string_size; // size of string table, in bytes - private int file_size; // size of file, in bytes; - private int elements; // number of elements in table - - private long length; // the length of the underlying file - - private final File name; // The name of the underlying file - - static private final int UNUSED_ENTRY = -1; - - static public final int KEYS = 0; - static public final int VALUES = 1; - static public final int ENTRIES = 2; - - private HashMap values; // A map of strings in the string table. - - FileChannel fc; // The underlying file channel. - - static final public class AccessMode - { - private final FileChannel.MapMode mapMode; - - static - { - READ_ONLY = new AccessMode(FileChannel.MapMode.READ_ONLY); - READ_WRITE = new AccessMode(FileChannel.MapMode.READ_WRITE); - PRIVATE = new AccessMode(FileChannel.MapMode.PRIVATE); - } - - public static final AccessMode READ_ONLY; - public static final AccessMode READ_WRITE; - public static final AccessMode PRIVATE; - - private AccessMode(FileChannel.MapMode mode) - { - this.mapMode = mode; - } - } - - private PersistentByteMap(File name) - { - this.name = name; - } - - public PersistentByteMap(String filename, AccessMode mode) - throws IOException - { - this(new File(filename), mode); - } - - public PersistentByteMap(File f, AccessMode mode) - throws IOException - { - name = f; - - if (mode == AccessMode.READ_ONLY) - { - FileInputStream fis = new FileInputStream(f); - fc = fis.getChannel(); - } - else - { - RandomAccessFile fos = new RandomAccessFile(f, "rw"); - fc = fos.getChannel(); - } - - length = fc.size(); - buf = fc.map(mode.mapMode, 0, length); - - int magic = getWord (MAGIC); - if (magic != 0x67636a64) /* "gcjd" */ - throw new IllegalArgumentException(f.getName()); - - table_base = getWord (TABLE_BASE); - capacity = getWord (CAPACITY); - string_base = getWord (STRING_BASE); - string_size = getWord (STRING_SIZE); - file_size = getWord (FILE_SIZE); - elements = getWord (ELEMENTS); - - // FIXME: Insert a bunch of sanity checks here - } - - private void init (PersistentByteMap m, File f, int capacity, int strtabSize) - throws IOException - { - f.createNewFile(); - RandomAccessFile raf = new RandomAccessFile(f, "rw"); - - { - // The user has explicitly provided a size for the table. - // We're going to make that size prime. This isn't - // strictly necessary but it can't hurt. - // - // We expand the size by 3/2 and round the result because the - // hash table is intolerably slow when more than 2/3 full. - - BigInteger size = new BigInteger(Integer.toString(((capacity*3)+1)/2)); - BigInteger two = BigInteger.ONE.add(BigInteger.ONE); - - if (size.getLowestSetBit() != 0) // A hard way to say isEven() - size = size.add(BigInteger.ONE); - - while (! size.isProbablePrime(10)) - size = size.add(two); - - this.capacity = capacity = size.intValue(); - } - - table_base = 64; - string_base = table_base + capacity * TABLE_ENTRY_SIZE; - string_size = 0; - file_size = string_base; - elements = 0; - - int totalFileSize = string_base + strtabSize; - - // Create the file; this rounds up the size of the file to a fixed - // number of 4k pages. - byte[] _4k = new byte[4096]; - for (long i = 0; i < totalFileSize; i+= 4096) - raf.write(_4k); - - fc = raf.getChannel(); - buf = fc.map(FileChannel.MapMode.READ_WRITE, 0, raf.length()); - - for (int i = 0; i < capacity; i++) - putKeyPos(UNUSED_ENTRY, i); - - putWord(0x67636a64, MAGIC); - putWord(0x01, VERSION); - putWord(capacity, CAPACITY); - putWord(table_base, TABLE_BASE); - putWord(string_base, STRING_BASE); - putWord(file_size, FILE_SIZE); - putWord(elements, ELEMENTS); - buf.force(); - - length = fc.size(); - string_size = 0; - } - - static public PersistentByteMap - emptyPersistentByteMap(File name, int capacity, int strtabSize) - throws IOException - { - PersistentByteMap m = new PersistentByteMap(name); - m.init(m, name, capacity, strtabSize); - return m; - } - - private int getWord (int index) - { - buf.position(index); - byte[] wordBuf = new byte[4]; - buf.get(wordBuf); - - int result = (int)wordBuf[0]&0xff; - result += ((int)wordBuf[1]&0xff) << 8; - result += ((int)wordBuf[2]&0xff) << 16; - result += ((int)wordBuf[3]&0xff) << 24; - return result; - } - - private void putWord (int word, int index) - { - buf.position(index); - byte[] wordBuf = new byte[4]; - wordBuf[0] = (byte)(word); - wordBuf[1] = (byte)(word >>> 8); - wordBuf[2] = (byte)(word >>> 16); - wordBuf[3] = (byte)(word >>> 24); - buf.put(wordBuf); - } - - public Set entrySet() - { - return null; - } - - private int getBucket(int n) - { - return table_base + (2*n * INT_SIZE); - } - - private int getKeyPos(int n) - { - return getWord(getBucket(n)); - } - - private int getValuePos(int n) - { - return getWord(getBucket(n) + INT_SIZE); - } - - private void putKeyPos(int index, int n) - { - putWord(index, getBucket(n)); - } - - private void putValuePos(int index, int n) - { - putWord(index, getBucket(n) + INT_SIZE); - } - - private byte[] getBytes(int n) - { - int len = getWord (string_base + n); - int base = string_base + n + INT_SIZE; - byte[] key = new byte[len]; - buf.position(base); - buf.get(key, 0, len); - return key; - } - - private int hash (byte[] b) - { - // We assume that the message digest is evenly distributed, so we - // only need to use a few bytes of it as the hash function. - long hashIndex - = ((b[0]&0xffL) - + ((b[1]&0xffL)<<8) - + ((b[2]&0xffL)<<16) - + ((b[3]&0xffL)<<24)); - long result = hashIndex % (long)capacity; - return (int)result; - } - - public byte[] get(byte[] digest) - { - int hashIndex = hash(digest); - - do - { - int k = getKeyPos(hashIndex); - if (k == UNUSED_ENTRY) - return null; - - if (Arrays.equals ((byte[])digest, getBytes(k))) - return getBytes(getValuePos(hashIndex)); - - // Use linear probing to resolve hash collisions. This may - // not be theoretically as good as open addressing, but it has - // good cache behviour. - hashIndex++; - hashIndex %= capacity; - } - while (true); - } - - public void put(byte[] digest, byte[] value) - throws IllegalAccessException - { - int hashIndex = hash(digest); - - if (elements >= capacity()) - throw new IllegalAccessException("Table Full: " + elements); - - do - { - int k = getKeyPos(hashIndex); - if (k == UNUSED_ENTRY) - { - int newKey = addBytes(digest); - putKeyPos(newKey, hashIndex); - int newValue = addBytes(value); - putValuePos(newValue, hashIndex); - elements++; - putWord(elements, ELEMENTS); - return; - } - else if (Arrays.equals (digest, getBytes(k))) - { - int newValue = addBytes((byte[])value); - putValuePos(newValue, hashIndex); - return; - } - - hashIndex++; - hashIndex %= capacity; - } - while (true); - } - - private int addBytes (byte[] data) - throws IllegalAccessException - { - if (data.length > 16) - { - // Keep track of long strings in the hope that we will be able - // to re-use them. - if (values == null) - { - values = new HashMap(); - - for (int i = 0; i < capacity; i++) - if (getKeyPos(i) != UNUSED_ENTRY) - { - int pos = getValuePos(i); - ByteWrapper bytes = new ByteWrapper(getBytes(pos)); - values.put(bytes, new Integer(pos)); - } - } - - { - Object result = values.get(new ByteWrapper(data)); - if (result != null) - { - // We already have this value in the string table - return ((Integer)result).intValue(); - } - } - } - - if (data.length + INT_SIZE >= this.length) - throw new IllegalAccessException("String table Full"); - - int extent = string_base+string_size; - int top = extent; - putWord(data.length, extent); - extent += INT_SIZE; - buf.position(extent); - buf.put(data, 0, data.length); - extent += data.length; - extent += INT_SIZE-1; - extent &= ~(INT_SIZE-1); // align - string_size = extent - string_base; - file_size = extent; - putWord (string_size, STRING_SIZE); - putWord (file_size, FILE_SIZE); - - if (data.length > 16) - values.put(new ByteWrapper(data), new Integer(top - string_base)); - - return top - string_base; - } - - public Iterator iterator(int type) - { - return new HashIterator(type); - } - - public int size() - { - return elements; - } - - public int stringTableSize() - { - return string_size; - } - - public int capacity() - { - // With the the table 2/3 full there will be on average 2 probes - // for a successful search and 5 probes for an unsuccessful one. - return capacity * 2/3; - } - - public void force() - { - buf.force(); - } - - public File getFile() - { - return name; - } - - // Close the map. Once this has been done, the map can no longer be - // used. - public void close() throws IOException - { - force(); - fc.close(); - } - - public void - putAll(PersistentByteMap t) - throws IllegalAccessException - { - // We can use a fast copy if the size of a map has not changed. - if (this.elements == 0 && t.capacity == this.capacity - && t.length == this.length) - { - this.buf.position(0); - t.buf.position(0); - this.buf.put(t.buf); - this.table_base = t.table_base; - this.string_base = t.string_base; - this.string_size = t.string_size; - this.file_size = t.file_size; - this.elements = t.elements; - if (t.values != null) - this.values = (HashMap)t.values.clone(); - return; - } - - // Otherwise do it the hard way. - Iterator iterator = t.iterator(PersistentByteMap.ENTRIES); - while (iterator.hasNext()) - { - PersistentByteMap.MapEntry entry - = (PersistentByteMap.MapEntry)iterator.next(); - this.put((byte[])entry.getKey(), (byte[])entry.getValue()); - } - } - - - private final class HashIterator implements Iterator - { - /** Current index in the physical hash table. */ - - private int idx; - private int count; - private final int type; - - /** - * Construct a new HashIterator with the supplied type. - * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES} - */ - HashIterator(int type) - { - this.type = type; - count = elements; - idx = 0; - } - - /** - * Returns true if the Iterator has more elements. - * @return true if there are more elements - * @throws ConcurrentModificationException if the HashMap was modified - */ - public boolean hasNext() - { - return count > 0; - } - - /** - * Returns the next element in the Iterator's sequential view. - * @return the next element - * @throws ConcurrentModificationException if the HashMap was modified - * @throws NoSuchElementException if there is none - */ - public Object next() - { - count--; - for (int i = idx; i < capacity; i++) - if (getKeyPos(i) != UNUSED_ENTRY) - { - idx = i+1; - if (type == VALUES) - return getBytes(getValuePos(i)); - if (type == KEYS) - return getBytes(getKeyPos(i)); - return new MapEntry(i, - getBytes(getKeyPos(i)), - getBytes(getValuePos(i))); - } - return null; - } - - /** - * Remove from the underlying collection the last element returned - * by next (optional operation). This method can be called only - * once after each call to <code>next()</code>. It does not affect - * what will be returned by subsequent calls to next. - * - * @throws IllegalStateException if next has not yet been called - * or remove has already been called since the last call - * to next. - * @throws UnsupportedOperationException if this Iterator does not - * support the remove operation. - */ - public void remove() - { - throw new UnsupportedOperationException(); - } - } - - static public final class MapEntry - { - private final Object key; - private final Object value; - private final int bucket; - - public MapEntry(int bucket, Object newKey, Object newValue) - { - this.key = newKey; - this.value = newValue; - this.bucket = bucket; - } - - public final Object getKey() - { - return key; - } - - public final Object getValue() - { - return value; - } - - public final int getBucket() - { - return bucket; - } - } - - // A wrapper class for a byte array that allows collections to be - // made. - private final class ByteWrapper - { - final byte[] bytes; - final int hash; - - public ByteWrapper (byte[] bytes) - { - int sum = 0; - this.bytes = bytes; - for (int i = 0; i < bytes.length; i++) - sum += bytes[i]; - hash = sum; - } - - public int hashCode() - { - return hash; - } - - public boolean equals(Object obj) - { - return Arrays.equals(bytes, ((ByteWrapper)obj).bytes); - } - } -} |
