KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > ejb > containers > util > cache > FIFOEJBObjectCache


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.ejb.containers.util.cache;
25
26 import com.sun.appserv.util.cache.Cache;
27 import com.sun.appserv.util.cache.CacheListener;
28 import com.sun.appserv.util.cache.Constants;
29
30 import java.util.Map JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Properties JavaDoc;
34 import java.util.ResourceBundle JavaDoc;
35
36 import java.util.logging.*;
37 import com.sun.logging.*;
38
39 /**
40  * A FIFO EJB(Local)Object cache that maintains reference count
41  *
42  * @author Mahesh Kannan
43  */

44 public class FIFOEJBObjectCache
45     extends LruCache
46     implements EJBObjectCache
47 {
48     protected int maxCacheSize;
49     protected String JavaDoc name;
50     protected EJBObjectCacheListener listener;
51     
52     protected Object JavaDoc refCountLock = new Object JavaDoc();
53     protected int totalRefCount = 0;
54     protected static boolean _printRefCount = false;
55     
56     
57     private static Logger _logger;
58     static {
59         _logger=LogDomains.getLogger(LogDomains.EJB_LOGGER);
60         
61         try {
62             Properties JavaDoc props = System.getProperties();
63             _printRefCount = (Boolean.valueOf(props.getProperty
64                 ("cache.printrefcount"))).booleanValue();
65         } catch (Exception JavaDoc ex) {
66             _logger.log(Level.FINE, "Cache PrintRefCount property ex", ex);
67         }
68     }
69     
70     /**
71      * default constructor
72      */

73     public FIFOEJBObjectCache(String JavaDoc name) {
74         this.name = name;
75     }
76     
77     /**
78      * constructor with specified timeout
79      */

80     public FIFOEJBObjectCache(String JavaDoc name, long timeout) {
81         super(timeout);
82         this.name = name;
83     }
84     
85     public void init(int maxEntries, int numberOfVictimsToSelect, long timeout,
86             float loadFactor, Properties JavaDoc props)
87     {
88         super.init(maxEntries, loadFactor, props);
89         super.timeout = timeout;
90         this.maxCacheSize = maxEntries;
91         _logger.log(Level.FINE, name + ": FIFOEJBObject cache created....");
92     }
93     
94     public void setEJBObjectCacheListener(EJBObjectCacheListener listener) {
95         this.listener = listener;
96     }
97     
98     public Object JavaDoc get(Object JavaDoc key) {
99         int hashCode = hash(key);
100         
101         return internalGet(hashCode, key, false);
102     }
103     
104     
105     public Object JavaDoc get(Object JavaDoc key, boolean incrementRefCount) {
106         int hashCode = hash(key);
107         
108         return internalGet(hashCode, key, incrementRefCount);
109     }
110     
111     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
112         int hashCode = hash(key);
113         
114         return internalPut(hashCode, key, value, -1, false);
115     }
116     
117     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value, boolean incrementRefCount) {
118         int hashCode = hash(key);
119         
120         return internalPut(hashCode, key, value, -1, incrementRefCount);
121     }
122     
123     
124     public Object JavaDoc remove(Object JavaDoc key) {
125         return internalRemove(key, true);
126     }
127     
128     public Object JavaDoc remove(Object JavaDoc key, boolean decrementRefCount) {
129         return internalRemove(key, decrementRefCount);
130     }
131     
132     protected boolean isThresholdReached() {
133         return listSize > maxCacheSize;
134     }
135     
136     protected void itemAccessed(CacheItem item) { }
137     
138     protected void itemRemoved(CacheItem item) {
139         LruCacheItem l = (LruCacheItem) item;
140         
141         // remove the item from the LRU list
142
synchronized (this) {
143             // if the item is already trimmed from the LRU list, nothing to do.
144
if (l.isTrimmed) {
145                 return;
146             }
147             
148             LruCacheItem prev = l.lPrev;
149             LruCacheItem next = l.lNext;
150             
151             l.isTrimmed = true;
152             
153             // patch up the neighbors and make sure head/tail are correct
154
if (prev != null)
155                 prev.lNext = next;
156             else
157                 head = next;
158             
159             if (next != null)
160                 next.lPrev = prev;
161             else
162                 tail = prev;
163             
164             l.lNext = l.lPrev = null;
165             
166             listSize--;
167         }
168     }
169     
170     protected Object JavaDoc internalGet(int hashCode, Object JavaDoc key,
171                                  boolean incrementRefCount) {
172         
173         int index = getIndex(hashCode);
174         Object JavaDoc value = null;
175         CacheItem item = null;
176         
177         synchronized (bucketLocks[index]) {
178             item = buckets[index];
179             
180             for (; item != null; item = item.next) {
181                 if ( (hashCode == item.hashCode) && eq(key, item.key) ) {
182                     break;
183                 }
184             }
185             
186             // update the stats in line
187
if (item != null) {
188                 value = item.getValue();
189                 if (incrementRefCount) {
190                     EJBObjectCacheItem eoItem = (EJBObjectCacheItem) item;
191                     eoItem.refCount++;
192                     if (_printRefCount) {
193                         incrementReferenceCount();
194                     }
195                     if (! eoItem.isTrimmed) {
196                         itemRemoved(eoItem);
197                     }
198                 }
199             }
200         }
201         
202         if (item != null)
203             incrementHitCount();
204         else
205             incrementMissCount();
206         
207         return value;
208     }
209     
210     protected Object JavaDoc internalPut(int hashCode, Object JavaDoc key, Object JavaDoc value,
211                                  int size, boolean incrementRefCount)
212     {
213         
214         int index = getIndex(hashCode);
215         
216         CacheItem item, oldItem = null, overflow = null;
217         EJBObjectCacheItem newItem = null;
218         Object JavaDoc oldValue = null;
219         int oldSize = 0;
220         
221         // lookup the item
222
synchronized (bucketLocks[index]) {
223             for (item = buckets[index]; item != null; item = item.next) {
224                 if ((hashCode == item.hashCode) && eq(key, item.key)) {
225                     oldItem = item;
226                     break;
227                 }
228             }
229             
230             // if there was no item in the cache, insert the given item
231
if (oldItem == null) {
232                 newItem = (EJBObjectCacheItem)
233                     createItem(hashCode, key, value, size);
234                 newItem.isTrimmed = incrementRefCount;
235                 
236                 // add the item at the head of the bucket list
237
newItem.next = buckets[index];
238                 buckets[index] = newItem;
239                 
240                 if (incrementRefCount) {
241                     newItem.refCount++;
242                     if (_printRefCount) {
243                         incrementReferenceCount();
244                     }
245                 } else {
246                     overflow = itemAdded(newItem);
247                 }
248             } else {
249                 oldValue = oldItem.getValue();
250                 if (incrementRefCount) {
251                     EJBObjectCacheItem oldEJBO = (EJBObjectCacheItem) oldItem;
252                     oldEJBO.refCount++;
253                     if (_printRefCount) {
254                         incrementReferenceCount();
255                     }
256                 }
257             }
258         }
259         
260         if (newItem != null) {
261             incrementEntryCount();
262             // make sure we are are not crossing the threshold
263
if ((overflow != null) && (listener != null)) {
264                 listener.handleOverflow(overflow.key);
265             }
266         }
267         
268         return oldValue;
269     }
270     
271     
272     public void print() {
273         System.out.println("EJBObjectCache:: size: " + getEntryCount() +
274                            "; listSize: " + listSize);
275         for (LruCacheItem run = head; run!=null; run=run.lNext) {
276             System.out.print("("+run.key+", "+run.value+") ");
277         }
278         System.out.println();
279     }
280     
281     protected Object JavaDoc internalRemove(Object JavaDoc key, boolean decrementRefCount) {
282         
283         int hashCode = hash(key);
284         int index = getIndex(hashCode);
285         
286         CacheItem prev = null, item = null;
287         
288         synchronized (bucketLocks[index]) {
289             for (item = buckets[index]; item != null; item = item.next) {
290                 if (hashCode == item.hashCode && key.equals(item.key)) {
291                     
292                     EJBObjectCacheItem eoItem = (EJBObjectCacheItem) item;
293                     if (decrementRefCount) {
294                         if (eoItem.refCount > 0) {
295                             eoItem.refCount--;
296                             if (_printRefCount) {
297                                 decrementReferenceCount();
298                             }
299                         }
300                     }
301                     
302                     if (eoItem.refCount > 0) {
303                         return null;
304                     }
305                     
306                     if (prev == null) {
307                         buckets[index] = item.next;
308                     } else {
309                         prev.next = item.next;
310                     }
311                     item.next = null;
312                     
313                     itemRemoved(item);
314                     
315                     break;
316                     
317                 }
318                 prev = item;
319             }
320         }
321         
322         if (item != null) {
323             decrementEntryCount();
324             incrementRemovalCount();
325             incrementHitCount();
326             return item.value;
327         } else {
328             incrementMissCount();
329             return null;
330         }
331         
332     }
333     
334     /*
335       protected void trimItem(CacheItem item) {
336     }
337      */

338     
339     protected CacheItem createItem(int hashCode, Object JavaDoc key, Object JavaDoc value,
340                                    int size) {
341         return new EJBObjectCacheItem(hashCode, key, value, size);
342     }
343     
344     protected static class EJBObjectCacheItem
345     extends LruCacheItem {
346         protected int refCount;
347         
348         protected EJBObjectCacheItem(int hashCode, Object JavaDoc key, Object JavaDoc value,
349                                      int size) {
350             super(hashCode, key, value, size);
351         }
352     }
353     
354     public Map JavaDoc getStats() {
355         Map JavaDoc map = new HashMap JavaDoc();
356         StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
357         
358         sbuf.append("(totalRef=").append(totalRefCount).append("; ");
359         
360         sbuf.append("listSize=").append(listSize)
361         .append("; curSize/totSize=").append(getEntryCount())
362         .append("/").append(maxEntries)
363         .append("; trim=").append(trimCount)
364         .append("; remove=").append(removalCount)
365         .append("; hit/miss=").append(hitCount).append("/").append(missCount)
366         .append(")");
367         map.put("["+name+"]", sbuf.toString());
368         return map;
369     }
370     
371     public void trimExpiredEntries(int maxCount) {
372         
373         int count = 0;
374         LruCacheItem item, lastItem = null;
375         long currentTime = System.currentTimeMillis();
376         
377         synchronized (this) {
378             // traverse LRU list till we reach a valid item; remove them at once
379
for (item = tail; item != null && count < maxCount;
380                  item = item.lPrev) {
381                 
382                 if ((timeout != NO_TIMEOUT) &&
383                     (item.lastAccessed + timeout) <= currentTime) {
384                     item.isTrimmed = true;
385                     lastItem = item;
386                     
387                     count++;
388                 } else {
389                     break;
390                 }
391             }
392             
393             // if there was at least one invalid item then item != tail.
394
if (item != tail) {
395                 lastItem.lPrev = null;
396                 
397                 if (item != null)
398                     item.lNext = null;
399                 else
400                     head = null;
401                 
402                 lastItem = tail; // record the old tail
403
tail = item;
404             }
405             listSize -= count;
406             trimCount += count;
407         }
408         
409         if (count > 0) {
410             
411             ArrayList JavaDoc localVictims = new ArrayList JavaDoc(count);
412             // trim the items from the BaseCache from the old tail backwards
413
for (item = lastItem; item != null; item = item.lPrev) {
414                 localVictims.add(item.key);
415             }
416             
417             if (listener != null) {
418                 listener.handleBatchOverflow(localVictims);
419             }
420         }
421     }
422     
423     protected void incrementReferenceCount() {
424         synchronized (refCountLock) {
425             totalRefCount++;
426         }
427     }
428     
429     protected void decrementReferenceCount() {
430         synchronized (refCountLock) {
431             totalRefCount--;
432         }
433     }
434     
435     protected void decrementReferenceCount(int count) {
436         synchronized (refCountLock) {
437             totalRefCount -= count;
438         }
439     }
440     
441     
442     static void unitTest_1()
443     throws Exception JavaDoc {
444         
445         FIFOEJBObjectCache cache = new FIFOEJBObjectCache("UnitTestCache");
446         cache.init(512, 0, 0, (float)1.0, null);
447         
448         int maxCount = 14;
449         ArrayList JavaDoc keys = new ArrayList JavaDoc();
450         for (int i=0; i<maxCount; i++) {
451             keys.add("K_"+i);
452         }
453         
454         for (int i=0; i<maxCount; i++) {
455             String JavaDoc key = (String JavaDoc) keys.get(i);
456             System.out.println("**** put(" + key + ", " + key + ", i" +
457                                ((i%2) == 0) + ")");
458             cache.put(key, key, ((i%2)==0));
459         }
460         
461         System.out.println("*** Only odd numbered keys must be printed ***");
462         cache.print();
463         System.out.println("************************************************");
464         
465         for (int i=0; i<maxCount; i++) {
466             String JavaDoc key = (String JavaDoc) keys.get(i);
467             cache.get(key, ((i%2)==1));
468         }
469         
470         System.out.println("**** NONE SHOULD BE PRINTED ****");
471         cache.print();
472         System.out.println("************************************************");
473         
474         cache.put("K__15", "K__15", true);
475         cache.put("K__16", "K__15", true);
476         cache.get("K__16", true); //K__16 has refCount == 2
477
cache.put("K__17", "K__17");//K__17 has refCount == 0
478

479         System.out.println("**** Only K__17 must be printed ****");
480         cache.print();
481         System.out.println("************************************************");
482         
483         for (int i=0; i<maxCount; i++) {
484             String JavaDoc key = (String JavaDoc) keys.get(i);
485             if (cache.remove(key) == null) {
486                 throw new RuntimeException JavaDoc("Remove must have returned null!!");
487             }
488         }
489         
490         Object JavaDoc k15 = cache.remove("K__15");
491         Object JavaDoc k16_1 = cache.remove("K__16");
492         Object JavaDoc k16_2 = cache.remove("K__16");
493         Object JavaDoc k17 = cache.remove("K__17");
494         
495         if (k15 == null) {
496             System.out.println("** FAILED for K_15");
497         }
498         
499         if (k16_1 != null) {
500             System.out.println("** FAILED for K_16_1");
501         }
502         
503         if (k16_2 == null) {
504             System.out.println("** FAILED for K_16_2");
505         }
506         
507         if (k17 == null) {
508             System.out.println("** FAILED for K_17");
509         }
510         
511         // Now the list id completely empty, add some more items
512
for (int i=0; i<maxCount; i+=2) {
513             String JavaDoc key = (String JavaDoc) keys.get(i);
514             cache.put(key, key, (i%4)==0);
515         }
516         cache.print();
517         
518         
519         //Make the FIFO list empty
520
for (int i=0; i<maxCount; i+=2) {
521             String JavaDoc key = (String JavaDoc) keys.get(i);
522             cache.get(key, true);
523         }
524         cache.print();
525         
526         // Now the FIFO list id completely empty, add some more items
527
for (int i=1; i<maxCount; i+=2) {
528             String JavaDoc key = (String JavaDoc) keys.get(i);
529             cache.put(key, key, (i%9)==0);
530         }
531         cache.print();
532     }
533     
534     public static void main(String JavaDoc[] args)
535         throws Exception JavaDoc
536     {
537         unitTest_1();
538     }
539     
540 }
541
Popular Tags