Cachepublic class Cache extends Object The caching mechanism designed to speed up the process
of Certificates/CRLs generation in the case of their repeated
generation.
It keeps correspondences between Objects (Certificates or CLRs)
and arrays of bytes on the base of which the Objects have been generated,
and provides the means to determine whether it contains the object built on
the base of particular encoded form or not. If there are such
objects they are returned from the cache, if not - newly generated
objects can be saved in the cache.
The process of Certificate/CRL generation
(implemented in X509CertFactoryImpl ) is accompanied with
prereading of the beginning of encoded form. This prefix is used to determine
whether provided form is PEM encoding or not.
So the use of the prefix is the first point to (approximately)
determine whether object to be generated is in the cache or not.
The failure of the predetermination process tells us that there were not
object generated from the encoded form with such prefix and we should
generate (decode) the object. If predetermination is successful,
we conduct the accurate search on the base of whole encoded form.
So to speed up the object generation process this caching mechanism provides
the following functionality:
1. With having of the beginning of the encoded form (prefix)
it is possible to predetermine whether object has already been
generated on the base of the encoding with the SIMILAR prefix or not.
This process is not computationally expensive and takes a little time.
But it prevents us from use of expensive full encoding
search in the case of its failure.
2. If predetermination ends with success, the whole encoding
form should be provided to make the final answer: whether object has
already been generated on the base of this PARTICULAR encoded form or not.
If it is so - the cached object is returned from the cache,
if not - new object should be generated and saved in the cache.
Note: The length of the prefixes of the encoded forms should not be
less than correspondence (default value is 28). |
Fields Summary |
---|
private static final long | HASH_MASK | private static final long | PREFIX_HASH_MASK | private static final int | INDEX_MASK | private final int | cache_size | private final int | prefix_size | private final long[] | hashes | private final byte[] | encodings | private final Object[] | cache | private final long[] | hashes_idx | private int | last_cached | private boolean | cache_is_full |
Constructors Summary |
---|
public Cache(int pref_size, int size)Creates the Cache object.
cache_size = size;
prefix_size = pref_size;
hashes = new long[cache_size];
hashes_idx = new long[cache_size];
encodings = new byte[cache_size][];
cache = new Object[cache_size];
| public Cache(int pref_size)Creates the Cache object of size of 9.
this(pref_size, 9);
| public Cache()Creates the Cache object of size of 9.
this(28, 9);
|
Methods Summary |
---|
public boolean | contains(long prefix_hash)Checks if there are any object in the cache generated
on the base of encoding with prefix corresponding
to the specified hash code.
int idx = -1*Arrays.binarySearch(hashes_idx, prefix_hash)-1;
if (idx == cache_size) {
return false;
} else {
return (hashes_idx[idx] & PREFIX_HASH_MASK) == prefix_hash;
}
| public java.lang.Object | get(long hash, byte[] encoding)Returns the object built on the base on the specified encoded
form if it is contained in the cache and null otherwise.
This method is computationally expensive and should be called only if
the method contains(long) for the hash code returned true.
hash |= getSuffHash(encoding);
int idx = -1*Arrays.binarySearch(hashes_idx, hash)-1;
if (idx == cache_size) {
return null;
}
while ((hashes_idx[idx] & HASH_MASK) == hash) {
int i = (int) (hashes_idx[idx] & INDEX_MASK) - 1;
if (Arrays.equals(encoding, encodings[i])) {
return cache[i];
}
idx++;
if (idx == cache_size) {
return null;
}
}
return null;
| public long | getHash(byte[] arr)Returns the hash code for the array. This code is used to
predetermine whether the object was built on the base of the
similar encoding or not (by means of contains(long) method),
to exactly determine whether object is contained in the cache or not,
and to put the object in the cache.
Note: parameter array should be of length not less than
specified by prefix_size (default 28)
long hash = 0;
for (int i=1; i<prefix_size; i++) {
hash += (arr[i] & 0xFF);
} // it takes about 2 bytes for prefix_size == 28
// shift to the correct place
hash = hash << 32;
return hash;
| private long | getSuffHash(byte[] arr)
long hash_addon = 0;
for (int i=arr.length-1; i>arr.length - prefix_size; i--) {
hash_addon += (arr[i] & 0xFF);
}
return hash_addon << 16;
| public void | put(long hash, byte[] encoding, java.lang.Object object)Puts the object into the cache.
// check for empty space in the cache
if (last_cached == cache_size) {
// so cache is full, will erase the first entry in the
// cache (oldest entry). it could be better to throw out
// rarely used value instead of oldest one..
last_cached = 0;
cache_is_full = true;
}
// index pointing to the item of the table to be overwritten
int index = last_cached++;
// improve the hash value with info from the tail of encoding
hash |= getSuffHash(encoding);
if (cache_is_full) {
// indexing hash value to be overwritten:
long idx_hash = (hashes[index] | (index+1));
int idx = Arrays.binarySearch(hashes_idx, idx_hash);
if (idx < 0) {
// it will never happen because we use saved hash value
// (hashes[index])
System.out.println("WARNING! "+idx); //$NON-NLS-1$
idx = -(idx + 1);
}
long new_hash_idx = (hash | (index + 1));
int new_idx = Arrays.binarySearch(hashes_idx, new_hash_idx);
if (new_idx >= 0) {
// it's possible when we write the same hash in the same cell
if (idx != new_idx) {
// it will never happen because we use the same
// hash and the same index in hash table
System.out.println("WARNING: "); //$NON-NLS-1$
System.out.println(">> idx: "+idx+" new_idx: "+new_idx); //$NON-NLS-1$ //$NON-NLS-2$
}
} else {
new_idx = -(new_idx + 1);
// replace in sorted array
if (new_idx > idx) {
System.arraycopy(hashes_idx, idx+1, hashes_idx, idx,
new_idx - idx - 1);
hashes_idx[new_idx-1] = new_hash_idx;
} else if (idx > new_idx) {
System.arraycopy(hashes_idx, new_idx, hashes_idx, new_idx+1,
idx - new_idx);
hashes_idx[new_idx] = new_hash_idx;
} else { // idx == new_idx
hashes_idx[new_idx] = new_hash_idx;
}
}
} else {
long idx_hash = (hash | (index + 1));
int idx = Arrays.binarySearch(hashes_idx, idx_hash);
if (idx < 0) {
// it will always be true because idx_hash depends on index
idx = -(idx + 1);
}
idx = idx - 1;
if (idx != cache_size - index - 1) {
// if not in the cell containing 0 (free cell), do copy:
System.arraycopy(hashes_idx, cache_size - index,
hashes_idx, cache_size - index - 1,
idx - (cache_size - index) + 1);
}
hashes_idx[idx] = idx_hash;
}
// overwrite the values in the tables:
hashes[index] = hash;
encodings[index] = encoding;
cache[index] = object;
|
|