View Javadoc

1   /***
2    *  Copyright 2003-2010 Terracotta, Inc.
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  
17  package net.sf.ehcache.store;
18  
19  import net.sf.ehcache.CacheException;
20  import net.sf.ehcache.Ehcache;
21  import net.sf.ehcache.Element;
22  import net.sf.ehcache.config.CacheConfiguration;
23  import net.sf.ehcache.pool.Pool;
24  import net.sf.ehcache.search.Attribute;
25  import net.sf.ehcache.search.Result;
26  import net.sf.ehcache.search.Results;
27  import net.sf.ehcache.search.aggregator.AggregatorInstance;
28  import net.sf.ehcache.search.attribute.AttributeExtractor;
29  import net.sf.ehcache.search.expression.Criteria;
30  import net.sf.ehcache.search.impl.AggregateOnlyResult;
31  import net.sf.ehcache.search.impl.BaseResult;
32  import net.sf.ehcache.search.impl.OrderComparator;
33  import net.sf.ehcache.search.impl.ResultImpl;
34  import net.sf.ehcache.search.impl.ResultsImpl;
35  import net.sf.ehcache.transaction.SoftLock;
36  
37  import java.util.ArrayList;
38  import java.util.Collections;
39  import java.util.HashMap;
40  import java.util.List;
41  import java.util.Map;
42  import java.util.concurrent.ConcurrentHashMap;
43  
44  /***
45   * A memory-only store with support for all caching features.
46   *
47   * @author Ludovic Orban
48   */
49  public final class MemoryOnlyStore extends FrontEndCacheTier<NullStore, MemoryStore> {
50  
51      private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
52  
53      private final Map<String, AttributeExtractor> attributeExtractors = new ConcurrentHashMap<String, AttributeExtractor>();
54      private final Map<String, Attribute> searchAttributes = new ConcurrentHashMap<String, Attribute>();
55  
56  
57      private MemoryOnlyStore(CacheConfiguration cacheConfiguration, NullStore cache, MemoryStore authority) {
58          super(cache, authority, cacheConfiguration.getCopyStrategy(), cacheConfiguration.isCopyOnWrite(), cacheConfiguration.isCopyOnRead());
59      }
60  
61      /***
62       * Create an instance of MemoryStore
63       * @param cache the cache
64       * @param onHeapPool the on heap pool
65       * @return an instance of MemoryStore
66       */
67      public static Store create(Ehcache cache, Pool onHeapPool) {
68          final NullStore nullStore = NullStore.create();
69          final MemoryStore memoryStore = MemoryStore.create(cache, onHeapPool);
70          return new MemoryOnlyStore(cache.getCacheConfiguration(), nullStore, memoryStore);
71      }
72  
73      /***
74       * {@inheritDoc}
75       */
76      @Override
77      public void setAttributeExtractors(Map<String, AttributeExtractor> extractors) {
78          this.attributeExtractors.putAll(extractors);
79  
80          for (String name : extractors.keySet()) {
81              searchAttributes.put(name, new Attribute(name));
82          }
83      }
84  
85      /***
86       * {@inheritDoc}
87       */
88      @Override
89      public Results executeQuery(StoreQuery query) {
90          Criteria c = query.getCriteria();
91  
92          List<AggregatorInstance<?>> aggregators = query.getAggregatorInstances();
93  
94  
95          boolean includeResults = query.requestsKeys() || query.requestsValues() || !query.requestedAttributes().isEmpty();
96  
97          ArrayList<Result> results = new ArrayList<Result>();
98  
99          boolean hasOrder = !query.getOrdering().isEmpty();
100 
101         boolean anyMatches = false;
102 
103         for (Element element : authority.elementSet()) {
104             if (!hasOrder && query.maxResults() >= 0 && results.size() == query.maxResults()) {
105                 break;
106             }
107             if (element.getObjectValue() instanceof SoftLock) {
108                 continue;
109             }
110 
111             if (c.execute(element, attributeExtractors)) {
112                 anyMatches = true;
113 
114                 if (includeResults) {
115                     final Map<String, Object> attributes;
116                     if (query.requestedAttributes().isEmpty()) {
117                         attributes = Collections.emptyMap();
118                     } else {
119                         attributes = new HashMap<String, Object>();
120                         for (Attribute attribute : query.requestedAttributes()) {
121                             String name = attribute.getAttributeName();
122                             attributes.put(name, attributeExtractors.get(name).attributeFor(element, name));
123                         }
124                     }
125 
126                     final Object[] sortAttributes;
127                     List<StoreQuery.Ordering> orderings = query.getOrdering();
128                     if (orderings.isEmpty()) {
129                         sortAttributes = EMPTY_OBJECT_ARRAY;
130                     } else {
131                         sortAttributes = new Object[orderings.size()];
132                         for (int i = 0; i < sortAttributes.length; i++) {
133                             String name = orderings.get(i).getAttribute().getAttributeName();
134                             sortAttributes[i] = attributeExtractors.get(name).attributeFor(element, name);
135                         }
136                     }
137 
138 
139                     results.add(new ResultImpl(element.getObjectKey(), element.getObjectValue(), query, attributes, sortAttributes));
140                 }
141 
142                 for (AggregatorInstance<?> aggregator : aggregators) {
143                     Attribute<?> attribute = aggregator.getAttribute();
144                     if (attribute == null) {
145                         aggregator.accept(null);
146                     } else {
147                         Object val = attributeExtractors.get(attribute.getAttributeName()).attributeFor(element,
148                                 attribute.getAttributeName());
149                         aggregator.accept(val);
150                     }
151                 }
152             }
153         }
154 
155         if (hasOrder) {
156             Collections.sort(results, new OrderComparator(query.getOrdering()));
157 
158             // trim results to max length if necessary
159             int max = query.maxResults();
160             if (max >= 0 && (results.size() > max)) {
161                 results.subList(max, results.size()).clear();
162                 results.trimToSize();
163             }
164         }
165 
166 
167         List<Object> aggregateResults = aggregators.isEmpty() ? Collections.emptyList() : new ArrayList<Object>();
168         for (AggregatorInstance<?> aggregator : aggregators) {
169             aggregateResults.add(aggregator.aggregateResult());
170         }
171 
172         if (anyMatches && !includeResults && !aggregateResults.isEmpty()) {
173             // add one row in the results if the only thing included was aggregators and anything matched
174             results.add(new AggregateOnlyResult(query));
175         }
176 
177 
178         if (!aggregateResults.isEmpty()) {
179             for (Result result : results) {
180                 // XXX: yucky cast
181                 ((BaseResult)result).setAggregateResults(aggregateResults);
182             }
183         }
184 
185         return new ResultsImpl(results, query.requestsKeys(), query.requestsValues(),
186                 !query.requestedAttributes().isEmpty(), anyMatches && !aggregateResults.isEmpty());
187     }
188 
189     /***
190      * {@inheritDoc}
191      */
192     @Override
193     public <T> Attribute<T> getSearchAttribute(String attributeName) throws CacheException {
194         return searchAttributes.get(attributeName);
195     }
196 
197     /***
198      * {@inheritDoc}
199      */
200     public Object getMBean() {
201         return null;
202     }
203 }