1
2
3
4
5
6
7
8
9 package ca.uhn.cache.impl;
10
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Date;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Set;
17
18 import jdsl.core.api.Position;
19 import jdsl.core.api.Tree;
20 import jdsl.core.ref.NodeTree;
21
22 import org.apache.commons.collections.CollectionUtils;
23
24 import ca.uhn.cache.CacheReasonEnum;
25 import ca.uhn.cache.IParamSpace;
26 import ca.uhn.cache.IQuery;
27 import ca.uhn.cache.IQueryParam;
28 import ca.uhn.cache.IQueryResult;
29 import ca.uhn.cache.ISemanticCache;
30 import ca.uhn.cache.VolatilityEnum;
31 import ca.uhn.cache.exception.CacheException;
32 import ca.uhn.cache.exception.QueryResultRetrievalCacheException;
33 import ca.uhn.cache.exception.QueryResultStorageCacheException;
34 import ca.uhn.cache.internal.IChunk;
35 import ca.uhn.cache.internal.IChunkStore;
36 import ca.uhn.cache.internal.IQueryResultStore;
37 import ca.uhn.cache.internal.exception.QueryResultStoreException;
38 import ca.uhn.cache.util.QueryUtil;
39
40 /***
41 * Semantic cache implementation that uses the chunk approach described in
42 *
43 * @inproceedings{ deshpande98caching, author = "Prasad M. Deshpande and
44 * Karthikeyan Ramasamy and Amit Shukla and Jeffrey F.
45 * Naughton", title = "Caching multidimensional queries using
46 * chunks", pages = "259--270", year = "1998", url =
47 * "citeseer.ist.psu.edu/deshpande98caching.html" }
48 *
49 * @author <a href="mailto:alexei.guevara@uhn.on.ca">Alexei Guevara </a>
50 * @version $Revision: 1.1 $ updated on $Date: 2005/01/24 22:52:33 $ by $Author: bryan_tripp $
51 */
52 public class ChunkBasedSemanticCache implements ISemanticCache {
53
54 private IParamSpace myParamSpace;
55 private IChunkStore myChunkStore;
56 private IQueryResultStore myQueryResultStore;
57
58 /***
59 *
60 */
61 public ChunkBasedSemanticCache() {
62 }
63
64 /***
65 * {@inheritDoc}
66 */
67 public IQuery[] remainder( IQuery theQuery, int theMaxGroups ) throws CacheException {
68 assert theQuery != null;
69 assert theMaxGroups >= 0;
70
71 IQuery[] retVal = null;
72
73
74
75 if ( theQuery.isEmpty() ) {
76 retVal = new IQuery[] {};
77 }
78 else {
79 List chunkEdges = new ArrayList();
80
81 Set queryParams = theQuery.getParameters();
82 for (Iterator queryParamsIter = queryParams.iterator(); queryParamsIter.hasNext();) {
83 IQueryParam queryParam = (IQueryParam) queryParamsIter.next();
84 IQueryParam[] edgesOnThisDimension = getParamSpace().chunk( queryParam );
85 chunkEdges.add( edgesOnThisDimension );
86 }
87
88 int maxParamsPerQuery = chunkEdges.size();
89
90 Tree queryParamsTree = new NodeTree();
91
92 Collection leafs = CollectionUtils.typedCollection( new ArrayList(), Position.class );
93 leafs.add( queryParamsTree.root() );
94
95 Collection newLeafs = CollectionUtils.typedCollection( new ArrayList(), Position.class );
96
97 for (Iterator chunkEdgesIter = chunkEdges.iterator(); chunkEdgesIter.hasNext();) {
98 IQueryParam[] chunkEdgesOnDimension = (IQueryParam[]) chunkEdgesIter.next();
99
100 for (int i = 0; i < chunkEdgesOnDimension.length; i++) {
101 IQueryParam queryParam = chunkEdgesOnDimension[i];
102
103 for (Iterator leafsIter = leafs.iterator(); leafsIter.hasNext();) {
104 Position leaf = (Position) leafsIter.next();
105 Position newLeaf = queryParamsTree.insertLastChild( leaf, queryParam );
106 newLeafs.add( newLeaf );
107 }
108
109 }
110
111 leafs.clear();
112 Collection tmp = leafs;
113 leafs = newLeafs;
114 newLeafs = tmp;
115
116 }
117
118 List nonCachedChunkBoundaries = new ArrayList();
119
120 for (Iterator leafsIter = leafs.iterator(); leafsIter.hasNext();) {
121 Position leaf = (Position) leafsIter.next();
122
123 IQuery query = new Query();
124 query.addParameter( (IQueryParam) leaf.element() );
125
126 Position parent = queryParamsTree.parent(leaf);
127 while ( parent != queryParamsTree.root() ) {
128 query.addParameter( (IQueryParam) parent.element() );
129 parent = queryParamsTree.parent( parent );
130 }
131
132 IChunk chunk = getChunkStore().get( query );
133 if ( chunk == null ) {
134 nonCachedChunkBoundaries.add( query );
135 }
136 }
137
138 if ( theMaxGroups != 0 ) {
139 retVal = getParamSpace().group(
140 (IQuery[]) nonCachedChunkBoundaries.toArray( new IQuery[ nonCachedChunkBoundaries.size() ] ),
141 theMaxGroups );
142 }
143 else {
144 retVal = (IQuery[]) nonCachedChunkBoundaries.toArray( new IQuery[ nonCachedChunkBoundaries.size() ] );
145 }
146 }
147
148 return retVal;
149 }
150
151 /***
152 * {@inheritDoc}
153 */
154 public IQueryResult get( IQuery theQuery ) throws CacheException {
155 IQueryResult retVal = null;
156
157 try {
158 retVal = getQueryResultStore().select( theQuery );
159 }
160 catch (QueryResultStoreException e) {
161 throw new QueryResultRetrievalCacheException( e, theQuery );
162 }
163
164 return retVal;
165 }
166
167 /***
168 * {@inheritDoc}
169 */
170 public void put( IQuery theQueryScope, IQueryResult theResult ) throws CacheException {
171 try {
172
173 getChunkStore().put(
174 theQueryScope,
175 VolatilityEnum.STABLE, new CacheReasonEnum[] { CacheReasonEnum.QUERY } );
176
177 getQueryResultStore().insert( theResult );
178 }
179 catch (QueryResultStoreException e) {
180 throw new QueryResultStorageCacheException( e, theQueryScope, theResult );
181 }
182 }
183
184 /***
185 * {@inheritDoc}
186 */
187 public void update( IQueryResult theResult ) throws CacheException {
188 try {
189
190 getQueryResultStore().insert( theResult );
191 }
192 catch (QueryResultStoreException e) {
193 throw new QueryResultStorageCacheException( "Error while updating a query result", e, null, theResult );
194 }
195 }
196
197 /***
198 * @return Returns the paramSpace.
199 */
200 public IParamSpace getParamSpace() {
201 return myParamSpace;
202 }
203
204 /***
205 * @param theParamSpace
206 * The paramSpace to set.
207 */
208 public void setParamSpace( IParamSpace theParamSpace ) {
209 myParamSpace = theParamSpace;
210 }
211
212 /***
213 * @return Returns the chunkStore.
214 */
215 public IChunkStore getChunkStore() {
216 return myChunkStore;
217 }
218
219 /***
220 * @param theChunkStore The chunkStore to set.
221 */
222 public void setChunkStore( IChunkStore theChunkStore ) {
223 myChunkStore = theChunkStore;
224 }
225
226 /***
227 * @return Returns the queryResultStore.
228 */
229 public IQueryResultStore getQueryResultStore() {
230 return myQueryResultStore;
231 }
232
233 /***
234 * @param theQueryResultStore The queryResultStore to set.
235 */
236 public void setQueryResultStore( IQueryResultStore theQueryResultStore ) {
237 myQueryResultStore = theQueryResultStore;
238 }
239
240 /***
241 * TODO: optimize!!
242 *
243 * @see ca.uhn.cache.ISemanticCache#getEarliestCacheTime(ca.uhn.cache.IQuery)
244 */
245 public Date getEarliestCacheTime(IQuery theQuery) throws CacheException {
246 IQuery[] regions = QueryUtil.chunk(theQuery, myParamSpace);
247
248 Date earliest = new Date(System.currentTimeMillis() + 20 * 60 * 1000);
249 for (int i = 0; i < regions.length; i++) {
250 IChunk chunk = myChunkStore.get(regions[i]);
251 if (chunk != null && chunk.getCacheTime().getTime() < earliest.getTime()) {
252 earliest = chunk.getCacheTime();
253 }
254 }
255
256 if (earliest.getTime() < System.currentTimeMillis()) {
257 return earliest;
258 } else {
259 return null;
260 }
261 }
262
263 }