001/*-------------------------------------------------------------------------+ 002| | 003| Copyright 2005-2011 The ConQAT Project | 004| | 005| Licensed under the Apache License, Version 2.0 (the "License"); | 006| you may not use this file except in compliance with the License. | 007| You may obtain a copy of the License at | 008| | 009| http://www.apache.org/licenses/LICENSE-2.0 | 010| | 011| Unless required by applicable law or agreed to in writing, software | 012| distributed under the License is distributed on an "AS IS" BASIS, | 013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 014| See the License for the specific language governing permissions and | 015| limitations under the License. | 016+-------------------------------------------------------------------------*/ 017package org.conqat.lib.commons.cache4j; 018 019import org.conqat.lib.commons.cache4j.backend.ICacheBackend; 020import org.conqat.lib.commons.error.NeverThrownRuntimeException; 021import org.conqat.lib.commons.factory.IParameterizedFactory; 022 023/** 024 * Basic implementation of a cache. 025 * 026 * @param <K> 027 * the key type. This must have both {@link Object#equals(Object)} 028 * and {@link Object#hashCode()} correctly implemented. 029 * @param <V> 030 * the value type. It is generally recommended to use an immutable 031 * type here, but this is not required. 032 * @param <X> 033 * the type of exception thrown. If no exception will be throws, use 034 * {@link NeverThrownRuntimeException}. 035 */ 036public class BasicCache<K, V, X extends Exception> implements ICache<K, V, X> { 037 038 /** The name of this cache (e.g. used for statistics). */ 039 private final String name; 040 041 /** The cache backend. */ 042 private ICacheBackend<K, V> backend; 043 044 /** The factory used to create new elements. */ 045 private final IParameterizedFactory<V, K, X> factory; 046 047 /** 048 * Counts the number of cache hits. This variable is not synchronized in any 049 * way, so multi-threaded usage of this class may lead to incorrect results. 050 * However, the amount of error is small enough to be tolerated, while the 051 * performance impact of synchronization is not. 052 */ 053 private int hits = 0; 054 055 /** 056 * Counts the number of cache misses. This variable is not synchronized in 057 * any way, so multi-threaded usage of this class may lead to incorrect 058 * results. However, the amount of error is small enough to be tolerated, 059 * while the performance impact of synchronization is not. 060 */ 061 private int misses = 0; 062 063 /** Accumulated cost of cache misses in milliseconds. */ 064 private long missCostMillis = 0; 065 066 /** Constructor. */ 067 public BasicCache(String name, IParameterizedFactory<V, K, X> factory, ICacheBackend<K, V> backend) { 068 this.name = name; 069 this.factory = factory; 070 this.backend = backend; 071 } 072 073 /** {@inheritDoc} */ 074 @Override 075 public String getName() { 076 return name; 077 } 078 079 /** {@inheritDoc} */ 080 @Override 081 public void clear(boolean allThreads) { 082 backend = backend.newInstance(); 083 } 084 085 /** {@inheritDoc} */ 086 @Override 087 public V obtain(K key) throws X { 088 V value = backend.retrieve(key); 089 090 if (value != null) { 091 hits++; 092 return value; 093 } 094 095 misses++; 096 097 long start = System.currentTimeMillis(); 098 099 value = factory.create(key); 100 backend.store(key, value); 101 102 missCostMillis += System.currentTimeMillis() - start; 103 104 return value; 105 } 106 107 /** {@inheritDoc} */ 108 @Override 109 public int getHits() { 110 return hits; 111 } 112 113 /** {@inheritDoc} */ 114 @Override 115 public int getMisses() { 116 return misses; 117 } 118 119 /** {@inheritDoc} */ 120 @Override 121 public long getMissCostMillis() { 122 return missCostMillis; 123 } 124}