~ubuntu-branches/ubuntu/trusty/ehcache/trusty

« back to all changes in this revision

Viewing changes to src/main/java/net/sf/ehcache/store/MemoryOnlyStore.java

  • Committer: Package Import Robot
  • Author(s): Emmanuel Bourg
  • Date: 2013-05-06 14:53:07 UTC
  • mfrom: (1.1.7) (2.1.8 sid)
  • Revision ID: package-import@ubuntu.com-20130506145307-v5bhw5yu70re00l3
Tags: 2.6.7-1
* Team upload.
* New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/**
2
 
 *  Copyright 2003-2010 Terracotta, Inc.
 
2
 *  Copyright Terracotta, Inc.
3
3
 *
4
4
 *  Licensed under the Apache License, Version 2.0 (the "License");
5
5
 *  you may not use this file except in compliance with the License.
16
16
 
17
17
package net.sf.ehcache.store;
18
18
 
19
 
import net.sf.ehcache.CacheException;
20
19
import net.sf.ehcache.Ehcache;
21
20
import net.sf.ehcache.Element;
22
21
import net.sf.ehcache.config.CacheConfiguration;
23
22
import net.sf.ehcache.pool.Pool;
24
23
import net.sf.ehcache.search.Attribute;
25
 
import net.sf.ehcache.search.Result;
26
24
import net.sf.ehcache.search.Results;
27
25
import net.sf.ehcache.search.aggregator.AggregatorInstance;
28
26
import net.sf.ehcache.search.attribute.AttributeExtractor;
 
27
import net.sf.ehcache.search.attribute.DynamicAttributesExtractor;
29
28
import net.sf.ehcache.search.expression.Criteria;
30
29
import net.sf.ehcache.search.impl.AggregateOnlyResult;
31
30
import net.sf.ehcache.search.impl.BaseResult;
 
31
import net.sf.ehcache.search.impl.GroupedResultImpl;
32
32
import net.sf.ehcache.search.impl.OrderComparator;
33
33
import net.sf.ehcache.search.impl.ResultImpl;
34
34
import net.sf.ehcache.search.impl.ResultsImpl;
35
 
import net.sf.ehcache.transaction.SoftLock;
 
35
import net.sf.ehcache.search.impl.SearchManager;
 
36
import net.sf.ehcache.transaction.SoftLockID;
 
37
 
 
38
import static net.sf.ehcache.search.expression.BaseCriteria.getExtractor;
36
39
 
37
40
import java.util.ArrayList;
 
41
import java.util.Collection;
38
42
import java.util.Collections;
39
43
import java.util.HashMap;
 
44
import java.util.HashSet;
 
45
import java.util.LinkedList;
40
46
import java.util.List;
41
47
import java.util.Map;
42
 
import java.util.concurrent.ConcurrentHashMap;
 
48
import java.util.Set;
 
49
import java.util.concurrent.locks.Lock;
43
50
 
44
51
/**
45
52
 * A memory-only store with support for all caching features.
46
53
 *
47
54
 * @author Ludovic Orban
48
55
 */
49
 
public final class MemoryOnlyStore extends FrontEndCacheTier<NullStore, MemoryStore> {
 
56
public class MemoryOnlyStore extends FrontEndCacheTier<NullStore, MemoryStore> {
50
57
 
51
58
    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
52
59
 
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());
 
60
    /**
 
61
     * Create a MemoryOnlyStore
 
62
     *
 
63
     * @param cacheConfiguration the cache configuration
 
64
     * @param authority the memory store
 
65
     */
 
66
    protected MemoryOnlyStore(CacheConfiguration cacheConfiguration, MemoryStore authority, SearchManager searchManager) {
 
67
        super(NullStore.create(), authority, cacheConfiguration.getCopyStrategy(), searchManager,
 
68
              cacheConfiguration.isCopyOnWrite(), cacheConfiguration.isCopyOnRead());
59
69
    }
60
70
 
61
71
    /**
62
 
     * Create an instance of MemoryStore
 
72
     * Create an instance of MemoryOnlyStore
63
73
     * @param cache the cache
64
74
     * @param onHeapPool the on heap pool
65
 
     * @return an instance of MemoryStore
 
75
     * @return an instance of MemoryOnlyStore
66
76
     */
67
77
    public static Store create(Ehcache cache, Pool onHeapPool) {
68
 
        final NullStore nullStore = NullStore.create();
69
78
        final MemoryStore memoryStore = NotifyingMemoryStore.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);
 
79
        final BruteForceSearchManager searchManager = new BruteForceSearchManager();
 
80
 
 
81
        MemoryOnlyStore memoryOnlyStore = new MemoryOnlyStore(cache.getCacheConfiguration(), memoryStore, searchManager);
 
82
        searchManager.setMemoryStore(memoryOnlyStore);
 
83
        return memoryOnlyStore;
 
84
    }
 
85
 
 
86
    /**
 
87
     * Get the underyling memory store element set
 
88
     *
 
89
     * @return element set
 
90
     */
 
91
    Collection<Element> elementSet() {
 
92
        return authority.elementSet();
 
93
    }
 
94
 
 
95
    /**
 
96
     * {@inheritDoc}
 
97
     */
 
98
    @Override
 
99
    public Element get(Object key) {
 
100
        if (key == null) {
 
101
            return null;
 
102
        }
 
103
 
 
104
        Lock lock = getLockFor(key).readLock();
 
105
        lock.lock();
 
106
        try {
 
107
            return copyElementForReadIfNeeded(authority.get(key));
 
108
        } finally {
 
109
            lock.unlock();
 
110
        }
 
111
    }
 
112
 
 
113
    /**
 
114
     * {@inheritDoc}
 
115
     */
 
116
    @Override
 
117
    public Element getQuiet(Object key) {
 
118
        if (key == null) {
 
119
            return null;
 
120
        }
 
121
 
 
122
        Lock lock = getLockFor(key).readLock();
 
123
        lock.lock();
 
124
        try {
 
125
            return copyElementForReadIfNeeded(authority.getQuiet(key));
 
126
        } finally {
 
127
            lock.unlock();
 
128
        }
 
129
    }
 
130
 
 
131
    /**
 
132
     * {@inheritDoc}
 
133
     */
 
134
    @Override
 
135
    public void setInMemoryEvictionPolicy(final Policy policy) {
 
136
        authority.setInMemoryEvictionPolicy(policy);
 
137
    }
 
138
 
 
139
    /**
 
140
     * {@inheritDoc}
 
141
     */
 
142
    @Override
 
143
    public Policy getInMemoryEvictionPolicy() {
 
144
        return authority.getInMemoryEvictionPolicy();
195
145
    }
196
146
 
197
147
    /**
200
150
    public Object getMBean() {
201
151
        return null;
202
152
    }
 
153
 
 
154
 
 
155
    /**
 
156
     * Brute force search implementation
 
157
     *
 
158
     * @author teck
 
159
     */
 
160
    protected static class BruteForceSearchManager implements SearchManager {
 
161
 
 
162
        private volatile MemoryOnlyStore memoryStore;
 
163
 
 
164
        /**
 
165
         * Create a BruteForceSearchManager
 
166
         */
 
167
        public BruteForceSearchManager() {
 
168
            //
 
169
        }
 
170
 
 
171
        /**
 
172
         * set the memory store
 
173
         *
 
174
         * @param memoryStore
 
175
         */
 
176
        public void setMemoryStore(MemoryOnlyStore memoryStore) {
 
177
            this.memoryStore = memoryStore;
 
178
        }
 
179
 
 
180
        @Override
 
181
        public void put(String cacheName, int segmentId, Element element, Map<String, AttributeExtractor> extractors,
 
182
                DynamicAttributesExtractor dynamicIndexer) {
 
183
            throw new UnsupportedOperationException();
 
184
        }
 
185
 
 
186
        @Override
 
187
        public Results executeQuery(String cacheName, StoreQuery query, Map<String, AttributeExtractor> extractors) {
 
188
            Criteria c = query.getCriteria();
 
189
 
 
190
            List<AggregatorInstance<?>> aggregators = query.getAggregatorInstances();
 
191
 
 
192
            final Set<Attribute<?>> groupByAttributes = query.groupByAttributes();
 
193
            final boolean isGroupBy = !groupByAttributes.isEmpty();
 
194
            boolean includeResults = query.requestsKeys() || query.requestsValues() || !query.requestedAttributes().isEmpty() || isGroupBy;
 
195
 
 
196
            boolean hasOrder = !query.getOrdering().isEmpty();
 
197
 
 
198
            final Map<Set<?>, BaseResult> groupByResults = new HashMap<Set<?>, BaseResult>();
 
199
            final Map<Set, List<AggregatorInstance<?>>> groupByAggregators = new HashMap<Set, List<AggregatorInstance<?>>>();
 
200
            final int maxResults = query.maxResults();
 
201
 
 
202
            Collection<Element> matches = new LinkedList<Element>();
 
203
 
 
204
            for (Element element : memoryStore.elementSet()) {
 
205
                element = memoryStore.copyElementForReadIfNeeded(element);
 
206
 
 
207
                if (element.getObjectValue() instanceof SoftLockID) {
 
208
                    continue;
 
209
                }
 
210
 
 
211
                if (c.execute(element, extractors)) {
 
212
                    if (!isGroupBy && !hasOrder && query.maxResults() >= 0 && matches.size() == query.maxResults()) {
 
213
                        break;
 
214
                    }
 
215
 
 
216
                    matches.add(element);
 
217
                }
 
218
            }
 
219
 
 
220
            Collection<BaseResult> results = isGroupBy ? groupByResults.values() : new ArrayList<BaseResult>();
 
221
 
 
222
            boolean anyMatches = !matches.isEmpty();
 
223
            for (Element element : matches) {
 
224
                if (includeResults) {
 
225
                    final Map<String, Object> attributes = getAttributeValues(query.requestedAttributes(), extractors, element);
 
226
                    final Object[] sortAttributes = getSortAttributes(query, extractors, element);
 
227
 
 
228
                    if (!isGroupBy) {
 
229
                        results.add(new ResultImpl(element.getObjectKey(), element.getObjectValue(), query, attributes, sortAttributes));
 
230
                    } else {
 
231
                        Map<String, Object> groupByValues = getAttributeValues(groupByAttributes, extractors, element);
 
232
                        Set<?> groupId = new HashSet(groupByValues.values());
 
233
                        BaseResult group = groupByResults.get(groupId);
 
234
                        if (group == null) {
 
235
                            group = new GroupedResultImpl(query, attributes, sortAttributes, Collections.EMPTY_LIST /* placeholder for now */,
 
236
                                    groupByValues);
 
237
                            groupByResults.put(groupId, group);
 
238
                        }
 
239
                        List<AggregatorInstance<?>> groupAggrs = groupByAggregators.get(groupId);
 
240
                        if (groupAggrs == null) {
 
241
                            groupAggrs = new ArrayList<AggregatorInstance<?>>(aggregators.size());
 
242
                            for (AggregatorInstance<?> aggr : aggregators) {
 
243
                                groupAggrs.add(aggr.createClone());
 
244
                            }
 
245
                            groupByAggregators.put(groupId, groupAggrs);
 
246
                        }
 
247
                        // Switch to per-record aggregators
 
248
                        aggregators = groupAggrs;
 
249
                    }
 
250
                }
 
251
 
 
252
                aggregate(aggregators, extractors, element);
 
253
 
 
254
            }
 
255
 
 
256
            if (hasOrder || isGroupBy) {
 
257
                if (isGroupBy) {
 
258
                    results = new ArrayList<BaseResult>(results);
 
259
                }
 
260
 
 
261
                if (hasOrder) {
 
262
                    Collections.sort((List<BaseResult>)results, new OrderComparator(query.getOrdering()));
 
263
                }
 
264
                // trim results to max length if necessary
 
265
                int max = query.maxResults();
 
266
                if (max >= 0 && (results.size() > max)) {
 
267
                    results = ((List<BaseResult>)results).subList(0, max);
 
268
                }
 
269
            }
 
270
 
 
271
            if (!aggregators.isEmpty()) {
 
272
                for (BaseResult result : results) {
 
273
                    if (isGroupBy) {
 
274
                        GroupedResultImpl group = (GroupedResultImpl)result;
 
275
                        Set<?> groupId = new HashSet(group.getGroupByValues().values());
 
276
                        aggregators = groupByAggregators.get(groupId);
 
277
                    }
 
278
                    setResultAggregators(aggregators, result);
 
279
                }
 
280
            }
 
281
 
 
282
            if (!isGroupBy && anyMatches && !includeResults && !aggregators.isEmpty()) {
 
283
                // add one row in the results if the only thing included was aggregators and anything matched
 
284
                BaseResult aggOnly = new AggregateOnlyResult(query);
 
285
                setResultAggregators(aggregators, aggOnly);
 
286
                results.add(aggOnly);
 
287
            }
 
288
 
 
289
            return new ResultsImpl((List)results, query.requestsKeys(), query.requestsValues(), !query.requestedAttributes().isEmpty(), anyMatches
 
290
                    && !aggregators.isEmpty());
 
291
        }
 
292
 
 
293
        private void setResultAggregators(List<AggregatorInstance<?>> aggregators, BaseResult result)
 
294
        {
 
295
            List<Object> aggregateResults = new ArrayList<Object>();
 
296
            for (AggregatorInstance<?> aggregator : aggregators) {
 
297
                aggregateResults.add(aggregator.aggregateResult());
 
298
            }
 
299
 
 
300
            if (!aggregateResults.isEmpty()) {
 
301
                result.setAggregateResults(aggregateResults);
 
302
            }
 
303
        }
 
304
 
 
305
        private Map<String, Object> getAttributeValues(Set<Attribute<?>> attributes, Map<String, AttributeExtractor> extractors, Element element) {
 
306
            final Map<String, Object> values;
 
307
            if (attributes.isEmpty()) {
 
308
                values = Collections.emptyMap();
 
309
            } else {
 
310
                values = new HashMap<String, Object>();
 
311
                for (Attribute attribute : attributes) {
 
312
                    String name = attribute.getAttributeName();
 
313
                    values.put(name, getExtractor(name, extractors).attributeFor(element, name));
 
314
                }
 
315
            }
 
316
            return values;
 
317
        }
 
318
 
 
319
        private void aggregate(List<AggregatorInstance<?>> aggregators, Map<String, AttributeExtractor> extractors, Element element) {
 
320
            for (AggregatorInstance<?> aggregator : aggregators) {
 
321
                Attribute<?> attribute = aggregator.getAttribute();
 
322
                if (attribute == null) {
 
323
                    aggregator.accept(null);
 
324
                } else {
 
325
                    Object val = getExtractor(attribute.getAttributeName(), extractors).attributeFor(element, attribute.getAttributeName());
 
326
                    aggregator.accept(val);
 
327
                }
 
328
            }
 
329
        }
 
330
 
 
331
        private Object[] getSortAttributes(StoreQuery query, Map<String, AttributeExtractor> extractors, Element element) {
 
332
            Object[] sortAttributes;
 
333
            List<StoreQuery.Ordering> orderings = query.getOrdering();
 
334
            if (orderings.isEmpty()) {
 
335
                sortAttributes = EMPTY_OBJECT_ARRAY;
 
336
            } else {
 
337
                sortAttributes = new Object[orderings.size()];
 
338
                for (int i = 0; i < sortAttributes.length; i++) {
 
339
                    String name = orderings.get(i).getAttribute().getAttributeName();
 
340
                    sortAttributes[i] = getExtractor(name, extractors).attributeFor(element, name);
 
341
                }
 
342
            }
 
343
 
 
344
            return sortAttributes;
 
345
        }
 
346
 
 
347
        @Override
 
348
        public void remove(String cacheName, Object uniqueKey, int segmentId, boolean isRemoval) {
 
349
            throw new UnsupportedOperationException();
 
350
        }
 
351
 
 
352
        @Override
 
353
        public void clear(String cacheName, int segmentId) {
 
354
            throw new UnsupportedOperationException();
 
355
        }
 
356
 
 
357
    }
 
358
 
203
359
}