EMMA Coverage Report (generated Thu Jan 20 11:39:44 EST 2011)
[all classes][com.hammurapi.store.local]

COVERAGE SUMMARY FOR SOURCE FILE [LocalStoreBase.java]

nameclass, %method, %block, %line, %
LocalStoreBase.java71%  (5/7)79%  (41/52)69%  (314/453)68%  (67.5/100)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class LocalStoreBase$20%   (0/1)0%   (0/2)0%   (0/12)0%   (0/3)
LocalStoreBase$2 (LocalStoreBase): void 0%   (0/1)0%   (0/6)0%   (0/2)
put (Object, Store$Handle): Store$Handle 0%   (0/1)0%   (0/6)0%   (0/1)
     
class LocalStoreBase$40%   (0/1)0%   (0/2)0%   (0/79)0%   (0/18)
LocalStoreBase$4 (LocalStoreBase): void 0%   (0/1)0%   (0/6)0%   (0/2)
run (): void 0%   (0/1)0%   (0/73)0%   (0/16)
     
class LocalStoreBase$Config100% (1/1)82%  (18/22)83%  (79/95)78%  (29/37)
setCleanupTaskThreshold (long): void 0%   (0/1)0%   (0/4)0%   (0/2)
setHandleFactory (HandleFactory): void 0%   (0/1)0%   (0/4)0%   (0/2)
setHandleStrength (LocalHandle$HandleStrength): void 0%   (0/1)0%   (0/4)0%   (0/2)
setWeakPrimaryKey (boolean): void 0%   (0/1)0%   (0/4)0%   (0/2)
LocalStoreBase$Config (): void 100% (1/1)100% (22/22)100% (6/6)
clone (): Object 100% (1/1)100% (3/3)100% (1/1)
getCleanupTaskThreshold (): long 100% (1/1)100% (3/3)100% (1/1)
getExecutorService (): ExecutorService 100% (1/1)100% (3/3)100% (1/1)
getHandleFactory (): HandleFactory 100% (1/1)100% (3/3)100% (1/1)
getHandleStrength (): LocalHandle$HandleStrength 100% (1/1)100% (3/3)100% (1/1)
getNoPkStore (): Collection 100% (1/1)100% (3/3)100% (1/1)
getObservableConverter (): ObservableConverter 100% (1/1)100% (3/3)100% (1/1)
getPkStore (): Map 100% (1/1)100% (3/3)100% (1/1)
getPrimaryKeyExtractor (): Extractor 100% (1/1)100% (3/3)100% (1/1)
isCacheExtracted (): boolean 100% (1/1)100% (3/3)100% (1/1)
isWeakPrimaryKey (): boolean 100% (1/1)100% (3/3)100% (1/1)
setCacheExtracted (boolean): void 100% (1/1)100% (4/4)100% (2/2)
setExecutorService (ExecutorService): void 100% (1/1)100% (4/4)100% (2/2)
setNoPkStore (Collection): void 100% (1/1)100% (4/4)100% (2/2)
setObservableConverter (ObservableConverter): void 100% (1/1)100% (4/4)100% (2/2)
setPkStore (Map): void 100% (1/1)100% (4/4)100% (2/2)
setPrimaryKeyExtractor (Extractor): void 100% (1/1)100% (4/4)100% (2/2)
     
class LocalStoreBase100% (1/1)84%  (16/19)86%  (193/225)83%  (33.9/41)
access$2 (LocalStoreBase): AtomicLong 0%   (0/1)0%   (0/3)0%   (0/1)
createIndexCollection (boolean, boolean, Comparator): Collection 0%   (0/1)0%   (0/4)0%   (0/1)
handleIndexAsynchException (Exception): void 0%   (0/1)0%   (0/3)0%   (0/2)
onRemoved (int): void 100% (1/1)58%  (11/19)67%  (2/3)
LocalStoreBase (LocalStoreBase$Config): void 100% (1/1)85%  (79/93)84%  (16/19)
access$0 (LocalStoreBase): TrackingLock 100% (1/1)100% (3/3)100% (1/1)
access$1 (LocalStoreBase): TrackingLock 100% (1/1)100% (3/3)100% (1/1)
createCache (): Map 100% (1/1)100% (10/10)100% (3/3)
createHandle (Object, Object, Map, Predicate []): Store$Handle 100% (1/1)100% (16/16)100% (1/1)
createIndex (Predicate, Extractor, Index$Type, boolean, Comparator): Abstract... 100% (1/1)100% (10/10)100% (1/1)
createMasterLock (): ReadWriteLock 100% (1/1)100% (24/24)100% (2/2)
getExecutorService (): ExecutorService 100% (1/1)100% (4/4)100% (1/1)
getIndices (): Collection 100% (1/1)100% (3/3)100% (1/1)
getNoPkStore (): Collection 100% (1/1)100% (11/11)100% (1/1)
getPkStore (): Map 100% (1/1)100% (4/4)100% (1/1)
getPrimaryKeyExtractor (): Extractor 100% (1/1)100% (4/4)100% (1/1)
readLock (): Lock 100% (1/1)100% (3/3)100% (1/1)
updateIndices (Store$Handle, boolean): void 100% (1/1)100% (5/5)100% (2/2)
writeLock (): Lock 100% (1/1)100% (3/3)100% (1/1)
     
class LocalStoreBase$1100% (1/1)100% (2/2)100% (10/10)100% (3/3)
LocalStoreBase$1 (LocalStoreBase): void 100% (1/1)100% (6/6)100% (2/2)
add (Store$Handle): boolean 100% (1/1)100% (4/4)100% (1/1)
     
class LocalStoreBase$3100% (1/1)100% (3/3)100% (14/14)100% (4/4)
LocalStoreBase$3 (LocalStoreBase): void 100% (1/1)100% (6/6)100% (2/2)
readLock (): Lock 100% (1/1)100% (4/4)100% (1/1)
writeLock (): Lock 100% (1/1)100% (4/4)100% (1/1)
     
class LocalStoreBase$Config$1100% (1/1)100% (2/2)100% (18/18)100% (3/3)
LocalStoreBase$Config$1 (LocalStoreBase$Config): void 100% (1/1)100% (6/6)100% (2/2)
createHandle (Store, Object, Object, Map, Predicate [], LocalHandle$HandleStr... 100% (1/1)100% (12/12)100% (1/1)

1package com.hammurapi.store.local;
2 
3import java.util.Collection;
4import java.util.Comparator;
5import java.util.Iterator;
6import java.util.LinkedList;
7import java.util.Map;
8import java.util.WeakHashMap;
9import java.util.concurrent.ConcurrentHashMap;
10import java.util.concurrent.ExecutorService;
11import java.util.concurrent.TimeUnit;
12import java.util.concurrent.atomic.AtomicLong;
13import java.util.concurrent.locks.Lock;
14import java.util.concurrent.locks.ReadWriteLock;
15import java.util.concurrent.locks.ReentrantReadWriteLock;
16 
17import com.hammurapi.common.ObservableConverter;
18import com.hammurapi.common.concurrent.CallerThreadExecutorService;
19import com.hammurapi.extract.Extractor;
20import com.hammurapi.extract.Predicate;
21import com.hammurapi.store.AbstractIndex;
22import com.hammurapi.store.AbstractStore;
23import com.hammurapi.store.DeputyReadWriteLock;
24import com.hammurapi.store.Index.Type;
25import com.hammurapi.store.Store;
26import com.hammurapi.store.StoreException;
27import com.hammurapi.store.TrackingLock;
28import com.hammurapi.store.local.LocalHandle.HandleStrength;
29 
30/**
31 * In-memory object store.
32 * @author Pavel Vlasov
33 *
34 * @param <T>
35 */
36public abstract class LocalStoreBase<T, PK, S extends Store<T,PK,S>> extends AbstractStore<T, PK, S> {
37        
38        /**
39         * Store configuration.
40         * @author Pavel Vlasov
41         *
42         */
43        public static class Config<T,PK,S extends Store<T,PK,S>> implements Cloneable {
44                
45                private final HandleFactory<T,PK,S,LocalHandle<T,PK,S>> DEFAULT_HANDLE_FACTORY = new HandleFactory<T, PK, S, LocalHandle<T,PK,S>>() {
46 
47                        @Override
48                        public LocalHandle<T, PK, S> createHandle(
49                                        S store,
50                                        T obj,
51                                        PK primaryKey,
52                                        Map<S, Map<Extractor<T, ? super PK, S>, ? super PK>> cache,
53                                        Predicate<T, S>[] validators,
54                                        HandleStrength handleStrength,
55                                        boolean cacheExtracted) {
56                                return new LocalHandle<T,PK,S>((LocalStoreBase<T, PK, S>) store, obj, primaryKey, cache, validators, handleStrength, cacheExtracted);
57                        }
58                        
59                };
60                
61                private long cleanupTaskThreshold = CLEANUP_TASK_THRESHOLD;                
62                private ExecutorService executorService;
63                private Extractor<T, PK, S> primaryKeyExtractor;
64                private boolean cacheExtracted = true;
65                private HandleStrength handleStrength = HandleStrength.STRONG;
66                private boolean weakPrimaryKey;
67                private Map<PK, Handle<T,PK,S>> pkStore;
68                private Collection<Handle<T,PK,S>> noPkStore;
69                private HandleFactory<T, PK, S, LocalHandle<T,PK,S>> handleFactory = DEFAULT_HANDLE_FACTORY;
70                private ObservableConverter<T> observableConverter;
71//                private TimeUnit statsTimeUnit;
72//                private boolean collectStats;
73                
74                // TODO Asynch index exception listener.
75//                BackingStore<T, PK> backingStore; 
76//                int writeBehindBuffer;
77//                long writeBehindDelay;
78//                TimeUnit writeBehindTimeUnit;
79                
80//                /**
81//                 * If time unit is set, store collects execution time statistics.
82//                 */
83//                public void setStatsTimeUnit(TimeUnit statsTimeUnit) {
84//                        this.statsTimeUnit = statsTimeUnit;
85//                }
86//                
87//                public TimeUnit getStatsTimeUnit() {
88//                        return statsTimeUnit;
89//                }
90//                
91//                /**
92//                 * If set to true, store collects execution statistics.
93//                 * @param collectStats
94//                 */
95//                public void setCollectStats(boolean collectStats) {
96//                        this.collectStats = collectStats;
97//                }
98//                
99//                public boolean isCollectStats() {
100//                        return collectStats;
101//                }
102                
103                /**
104                 * @param cleanupTaskThreshold When number of invalidated (removed) handles exceeds this
105                 * threshold, the store performs cleanup of internal collections.
106                 */
107                public void setCleanupTaskThreshold(long cleanupTaskThreshold) {
108                        this.cleanupTaskThreshold = cleanupTaskThreshold;
109                }
110                
111                /**
112                 * @return Cleanup task threshold.
113                 */
114                public long getCleanupTaskThreshold() {
115                        return cleanupTaskThreshold;
116                }
117                
118                @Override
119                public Object clone() throws CloneNotSupportedException {
120                        return super.clone();
121                }
122 
123                /**
124                 * @return Executor service. If null, all operations are performed in the caller thread.
125                 */
126                public ExecutorService getExecutorService() {
127                        return executorService;
128                }
129 
130                /**
131                 * 
132                 * @param executorService Executor service. If null, all operations are performed in the caller thread.
133                 */
134                public void setExecutorService(ExecutorService executorService) {
135                        this.executorService = executorService;
136                }
137 
138                
139                public Extractor<T, PK, S> getPrimaryKeyExtractor() {
140                        return primaryKeyExtractor;
141                }
142 
143                /**
144                 * @param primaryKeyExtractor Primary key extractor. Can be null.
145                 */
146                public void setPrimaryKeyExtractor(
147                                Extractor<T, PK, S> primaryKeyExtractor) {
148                        this.primaryKeyExtractor = primaryKeyExtractor;
149                }
150 
151                public boolean isCacheExtracted() {
152                        return cacheExtracted;
153                }
154 
155                /**
156                 * @param cacheExtracted If true, values extracted from stored objects are cached until object is updated 
157                 * through update() or put() methods. Default value is true.
158                 */
159                public void setCacheExtracted(boolean cacheExtracted) {
160                        this.cacheExtracted = cacheExtracted;
161                }
162                
163                public HandleStrength getHandleStrength() {
164                        return handleStrength;
165                }
166 
167                /**
168                 * @param handleStrength Handle strength. Default handle strength is HARD.
169                 */
170                public void setHandleStrength(HandleStrength handleStrength) {
171                        this.handleStrength = handleStrength;
172                }
173 
174                public boolean isWeakPrimaryKey() {
175                        return weakPrimaryKey;
176                }
177 
178                /**
179                 * @param weakStore If true, the store uses WeakHashMap if primary key is set and
180                 * pkStore is not set explicitly.
181                 */
182                public void setWeakPrimaryKey(boolean weakPrimaryKey) {
183                        this.weakPrimaryKey = weakPrimaryKey;
184                }
185 
186                public Map<PK, Handle<T, PK, S>> getPkStore() {
187                        return pkStore;
188                }
189 
190                /**
191                 * @param pkStore Explicitly provided pkStore instance.
192                 */
193                public void setPkStore(Map<PK, Handle<T, PK, S>> pkStore) {
194                        this.pkStore = pkStore;
195                }
196 
197                public Collection<Handle<T, PK, S>> getNoPkStore() {
198                        return noPkStore;
199                }
200 
201                /**
202                 * @param noPkStore Explicitly provided noPkStore instance.
203                 */
204                public void setNoPkStore(Collection<Handle<T, PK, S>> noPkStore) {
205                        this.noPkStore = noPkStore;
206                }
207                
208                public void setHandleFactory(HandleFactory<T, PK, S, LocalHandle<T, PK, S>> handleFactory) {
209                        this.handleFactory = handleFactory;
210                }
211                
212                public HandleFactory<T, PK, S, LocalHandle<T, PK, S>> getHandleFactory() {
213                        return handleFactory;
214                }
215                
216                public void setObservableConverter(ObservableConverter<T> observableConverter) {
217                        this.observableConverter = observableConverter;
218                }
219                
220                public ObservableConverter<T> getObservableConverter() {
221                        return observableConverter;
222                }
223        }
224 
225        private static final long CLEANUP_TASK_THRESHOLD = 1000;
226        
227        protected Config<T,PK,S> config;
228        
229        @SuppressWarnings("unchecked")
230        protected LocalStoreBase(Config<T,PK,S> config) {
231                try {
232                        this.config = (Config<T, PK, S>) config.clone();
233                } catch (CloneNotSupportedException e) {
234                        throw new StoreException(e);
235                }
236                
237                if (this.config.getExecutorService()==null) {
238                        this.config.setExecutorService(CallerThreadExecutorService.INSTANCE);
239                }
240 
241                if (this.config.getPrimaryKeyExtractor()==null) {
242                        if (this.config.getNoPkStore()==null) {
243                                this.config.setNoPkStore(new LinkedList<Handle<T,PK,S>>() { // TODO - Address uniqueness
244                                        
245                                        // Synchronized for situations when updaters perform inserts.
246                                        public synchronized boolean add(Handle<T,PK,S> e) {
247                                                return super.add(e);
248                                        }
249                                });                                
250                        }
251                } else {
252                        if (this.config.getPkStore()==null) {
253                                if (this.config.isWeakPrimaryKey()) {
254                                        this.config.setPkStore(new WeakHashMap<PK, Handle<T,PK,S>>() {
255                                                
256                                                // Synchronized for situations when updaters perform inserts.
257                                                public synchronized Handle<T,PK,S> put(PK key, Handle<T,PK,S> value) {
258                                                        return super.put(key, value);
259                                                };
260                                        
261                                        });
262                                } else {
263                                        this.config.setPkStore(new ConcurrentHashMap<PK, Handle<T,PK,S>>());
264                                }
265                        }
266                }
267                
268        }
269        
270        private ReentrantReadWriteLock storeLock = new ReentrantReadWriteLock();
271        private TrackingLock readLock = new LocalTrackingLock(storeLock.readLock());
272        private TrackingLock writeLock = new LocalTrackingLock(storeLock.writeLock());
273 
274        @Override
275        public Lock readLock() {
276                return readLock;
277        }
278 
279        @Override
280        public Lock writeLock() {
281                return writeLock;
282        }
283 
284        @Override
285        protected Map<PK, Handle<T, PK, S>> getPkStore() {
286                return config.getPkStore();
287        }
288        
289        @Override
290        protected Collection<Handle<T, PK, S>> getNoPkStore() {
291                return getPrimaryKeyExtractor()==null ? config.getNoPkStore() : getPkStore().values();
292        }
293 
294        @Override
295        protected ExecutorService getExecutorService() {
296                return config.getExecutorService();
297        }
298        
299 
300        @SuppressWarnings("unchecked")
301        @Override
302        protected Handle<T, PK, S> createHandle(
303                        T obj,
304                        PK primaryKey,
305                        Map<S, Map<Extractor<T, ? super PK, S>, ? super PK>> cache, 
306                        Predicate<T, S>[] validators) {
307                return config.getHandleFactory().createHandle((S) this, obj, primaryKey, cache, validators, config.getHandleStrength(), config.isCacheExtracted());
308        }
309 
310        @Override
311        protected Collection<Handle<T, PK, S>> createIndexCollection(
312                        boolean unique, 
313                        boolean ordered, 
314                        Comparator<T> comparator) {
315                
316                throw new UnsupportedOperationException();
317        }
318 
319        @Override
320        protected Map<S, Map<Extractor<T, ? super PK, S>, ? super PK>> createCache() {
321                if (config.isCacheExtracted()) {
322                        return new ConcurrentHashMap<S, Map<Extractor<T, ? super PK, S>, ? super PK>>();
323                }
324                return null;
325        }
326 
327        @Override
328        protected ReadWriteLock createMasterLock() {                
329                ReadWriteLock master = new ReadWriteLock() {
330                        
331                        @Override
332                        public Lock writeLock() {
333                                return writeLock;
334                        }
335                        
336                        @Override
337                        public Lock readLock() {
338                                return readLock;
339                        }
340                };
341                return new DeputyReadWriteLock(master, readLock.isLocked() || writeLock.isLocked(), writeLock.isLocked());
342        }
343        
344        private AtomicLong removedCounter = new AtomicLong(0);
345 
346        /**
347         * If there is a lot of cleared handles this method posts a task to compact store collections..
348         */
349        @Override
350        protected void onRemoved(int removed) {
351                if (removedCounter.addAndGet(removed)>config.getCleanupTaskThreshold()) {
352                        getExecutorService().submit(new Runnable() {
353 
354                                @Override
355                                public void run() {
356                                        writeLock().lock();
357                                        int cleanedUp = 0;
358                                        try {
359                                                Iterator<Handle<T, PK, S>> it = getNoPkStore().iterator(); // Takes care of both map and collection.
360                                                while (it.hasNext()) {
361                                                        Handle<T, PK, S> h = it.next();
362                                                        if (!h.isValid()) {
363                                                                it.remove();
364                                                                ++cleanedUp;
365                                                        }
366                                                }
367                                                
368                                                for (AbstractIndex<T,PK,?,S> index: getIndices()) {
369                                                        index.cleanup();
370                                                }
371                                        } finally {
372                                                writeLock().unlock();
373                                                if (cleanedUp>0) {
374                                                        removedCounter.addAndGet(-cleanedUp);
375                                                }
376                                        }
377                                }
378                                
379                        });
380                }
381        }
382 
383        @Override
384        public Extractor<T, PK, S> getPrimaryKeyExtractor() {
385                return config.getPrimaryKeyExtractor();
386        }
387        
388        private Collection<AbstractIndex<T, PK, ?, S>> indices = new LinkedList<AbstractIndex<T,PK,?,S>>();
389 
390        @Override
391        protected Collection<AbstractIndex<T, PK, ?, S>> getIndices() {
392                return indices;
393        }
394        
395        @Override
396        protected <V> AbstractIndex<T, PK, V, S> createIndex(
397                        Predicate<T, S> predicate,
398                        Extractor<T, V, S> extractor, 
399                        Type type,
400                        boolean ordered, 
401                        Comparator<V> comparator) {
402                
403                return new LocalIndex<T, PK, V, S>(predicate, extractor, type, ordered, comparator, this);
404        }
405 
406        protected void handleIndexAsynchException(Exception e) {
407                e.printStackTrace();                
408        }
409        
410        /**
411         * To make it visible to LocalHandle.
412         */
413        @Override
414        protected void updateIndices(Handle<T, PK, S> handle, boolean isNew) {
415                super.updateIndices(handle, isNew);
416        }
417        
418        @Override
419        protected abstract S createDeputy();
420}

[all classes][com.hammurapi.store.local]
EMMA 2.0.5312 EclEmma Fix 2 (C) Vladimir Roubtsov