org.glassfish.persistence.ejb.entitybean.container.cache.FIFOEJBObjectCache Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project for IBM JDK
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.glassfish.persistence.ejb.entitybean.container.cache;
import com.sun.appserv.util.cache.Cache;
import com.sun.appserv.util.cache.CacheListener;
import com.sun.appserv.util.cache.Constants;
import com.sun.ejb.containers.util.cache.LruEJBCache;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.logging.*;
import com.sun.logging.*;
/**
* A FIFO EJB(Local)Object cache that maintains reference count
*
* @author Mahesh Kannan
*/
public class FIFOEJBObjectCache
extends LruEJBCache
implements EJBObjectCache
{
protected int maxCacheSize;
protected String name;
protected EJBObjectCacheListener listener;
protected Object refCountLock = new Object();
protected int totalRefCount = 0;
protected static final boolean _printRefCount =
Boolean.getBoolean("cache.printrefcount");
private static final Logger _logger =
LogDomains.getLogger(FIFOEJBObjectCache.class, LogDomains.EJB_LOGGER);
/**
* default constructor
*/
public FIFOEJBObjectCache(String name) {
this.name = name;
}
/**
* constructor with specified timeout
*/
public FIFOEJBObjectCache(String name, long timeout) {
super();
setTimeout(timeout);
this.name = name;
}
public void init(int maxEntries, int numberOfVictimsToSelect, long timeout,
float loadFactor, Properties props)
{
super.init(maxEntries, loadFactor, props);
super.timeout = timeout;
this.maxCacheSize = maxEntries;
_logger.log(Level.FINE, name + ": FIFOEJBObject cache created....");
}
public void setEJBObjectCacheListener(EJBObjectCacheListener listener) {
this.listener = listener;
}
public Object get(Object key) {
int hashCode = hash(key);
return internalGet(hashCode, key, false);
}
public Object get(Object key, boolean incrementRefCount) {
int hashCode = hash(key);
return internalGet(hashCode, key, incrementRefCount);
}
public Object put(Object key, Object value) {
int hashCode = hash(key);
return internalPut(hashCode, key, value, -1, false);
}
public Object put(Object key, Object value, boolean incrementRefCount) {
int hashCode = hash(key);
return internalPut(hashCode, key, value, -1, incrementRefCount);
}
public Object remove(Object key) {
return internalRemove(key, true);
}
public Object remove(Object key, boolean decrementRefCount) {
return internalRemove(key, decrementRefCount);
}
protected boolean isThresholdReached() {
return listSize > maxCacheSize;
}
protected void itemAccessed(CacheItem item) { }
protected void itemRemoved(CacheItem item) {
// LruCacheItem(more specifically EJBObjectCacheItem) should always be used in conjunction with FIFOEJBObjectCache
assert item instanceof LruCacheItem;
LruCacheItem l = (LruCacheItem) item;
// remove the item from the LRU list
synchronized (this) {
// if the item is already trimmed from the LRU list, nothing to do.
if (l.isTrimmed()) {
return;
}
LruCacheItem prev = l.getLPrev();
LruCacheItem next = l.getLNext();
l.setTrimmed(true);
// patch up the neighbors and make sure head/tail are correct
if (prev != null)
prev.setLNext(next);
else
head = next;
if (next != null)
next.setLPrev(prev);
else
tail = prev;
l.setLNext(null);
l.setLPrev(null);
listSize--;
}
}
protected Object internalGet(int hashCode, Object key,
boolean incrementRefCount) {
int index = getIndex(hashCode);
Object value = null;
CacheItem item = null;
synchronized (bucketLocks[index]) {
item = buckets[index];
for (; item != null; item = item.getNext()) {
if ( (hashCode == item.getHashCode()) && eq(key, item.getKey()) ) {
break;
}
}
// update the stats in line
if (item != null) {
value = item.getValue();
if (incrementRefCount) {
// EJBObjectCacheItem should always be used in conjunction with FIFOEJBObjectCache
assert item instanceof EJBObjectCacheItem;
EJBObjectCacheItem eoItem = (EJBObjectCacheItem) item;
eoItem.refCount++;
if (_printRefCount) {
incrementReferenceCount();
}
if (! eoItem.isTrimmed()) {
itemRemoved(eoItem);
}
}
}
}
if (item != null)
incrementHitCount();
else
incrementMissCount();
return value;
}
protected Object internalPut(int hashCode, Object key, Object value,
int size, boolean incrementRefCount)
{
int index = getIndex(hashCode);
CacheItem item, oldItem = null, overflow = null;
EJBObjectCacheItem newItem = null;
Object oldValue = null;
int oldSize = 0;
// lookup the item
synchronized (bucketLocks[index]) {
for (item = buckets[index]; item != null; item = item.getNext()) {
if ((hashCode == item.getHashCode()) && eq(key, item.getKey())) {
oldItem = item;
break;
}
}
// if there was no item in the cache, insert the given item
if (oldItem == null) {
newItem = (EJBObjectCacheItem)
createItem(hashCode, key, value, size);
newItem.setTrimmed(incrementRefCount);
// add the item at the head of the bucket list
newItem.setNext( buckets[index] );
buckets[index] = newItem;
if (incrementRefCount) {
newItem.refCount++;
if (_printRefCount) {
incrementReferenceCount();
}
} else {
overflow = itemAdded(newItem);
}
} else {
oldValue = oldItem.getValue();
if (incrementRefCount) {
// EJBObjectCacheItem should always be used in conjunction with FIFOEJBObjectCache
assert oldItem instanceof EJBObjectCacheItem;
EJBObjectCacheItem oldEJBO = (EJBObjectCacheItem) oldItem;
oldEJBO.refCount++;
if (_printRefCount) {
incrementReferenceCount();
}
}
}
}
if (newItem != null) {
incrementEntryCount();
// make sure we are are not crossing the threshold
if ((overflow != null) && (listener != null)) {
listener.handleOverflow(overflow.getKey());
}
}
return oldValue;
}
public void print() {
System.out.println("EJBObjectCache:: size: " + getEntryCount() +
"; listSize: " + listSize);
for (LruCacheItem run = head; run!=null; run=run.getLNext()) {
System.out.print("("+run.getKey()+", "+run.getValue()+") ");
}
System.out.println();
}
protected Object internalRemove(Object key, boolean decrementRefCount) {
int hashCode = hash(key);
int index = getIndex(hashCode);
CacheItem prev = null, item = null;
synchronized (bucketLocks[index]) {
for (item = buckets[index]; item != null; item = item.getNext()) {
if (hashCode == item.getHashCode() && key.equals(item.getKey())) {
// EJBObjectCacheItem should always be used in conjunction with FIFOEJBObjectCache
assert item instanceof EJBObjectCacheItem;
EJBObjectCacheItem eoItem = (EJBObjectCacheItem) item;
if (decrementRefCount) {
if (eoItem.refCount > 0) {
eoItem.refCount--;
if (_printRefCount) {
decrementReferenceCount();
}
}
}
if (eoItem.refCount > 0) {
return null;
}
if (prev == null) {
buckets[index] = item.getNext();
} else {
prev.setNext( item.getNext() );
}
item.setNext( null );
itemRemoved(item);
break;
}
prev = item;
}
}
if (item != null) {
decrementEntryCount();
incrementRemovalCount();
incrementHitCount();
return item.getValue();
} else {
incrementMissCount();
return null;
}
}
/*
protected void trimItem(CacheItem item) {
}
*/
protected CacheItem createItem(int hashCode, Object key, Object value,
int size) {
return new EJBObjectCacheItem(hashCode, key, value, size);
}
protected static class EJBObjectCacheItem
extends LruCacheItem {
protected int refCount;
protected EJBObjectCacheItem(int hashCode, Object key, Object value,
int size) {
super(hashCode, key, value, size);
}
}
public Map getStats() {
Map map = new HashMap();
StringBuffer sbuf = new StringBuffer();
sbuf.append("(totalRef=").append(totalRefCount).append("; ");
sbuf.append("listSize=").append(listSize)
.append("; curSize/totSize=").append(getEntryCount())
.append("/").append(maxEntries)
.append("; trim=").append(trimCount)
.append("; remove=").append(removalCount)
.append("; hit/miss=").append(hitCount).append("/").append(missCount)
.append(")");
map.put("["+name+"]", sbuf.toString());
return map;
}
public void trimExpiredEntries(int maxCount) {
int count = 0;
LruCacheItem item, lastItem = null;
long currentTime = System.currentTimeMillis();
synchronized (this) {
// traverse LRU list till we reach a valid item; remove them at once
for (item = tail; item != null && count < maxCount;
item = item.getLPrev()) {
if ((timeout != NO_TIMEOUT) &&
(item.getLastAccessed() + timeout) <= currentTime) {
item.setTrimmed(true);
lastItem = item;
count++;
} else {
break;
}
}
// if there was at least one invalid item then item != tail.
if (item != tail) {
lastItem.setLPrev(null);
if (item != null)
item.setLNext(null);
else
head = null;
lastItem = tail; // record the old tail
tail = item;
}
listSize -= count;
trimCount += count;
}
if (count > 0) {
ArrayList localVictims = new ArrayList(count);
// trim the items from the BaseCache from the old tail backwards
for (item = lastItem; item != null; item = item.getLPrev()) {
localVictims.add(item.getKey());
}
if (listener != null) {
listener.handleBatchOverflow(localVictims);
}
}
}
protected void incrementReferenceCount() {
synchronized (refCountLock) {
totalRefCount++;
}
}
protected void decrementReferenceCount() {
synchronized (refCountLock) {
totalRefCount--;
}
}
protected void decrementReferenceCount(int count) {
synchronized (refCountLock) {
totalRefCount -= count;
}
}
static void unitTest_1()
throws Exception {
FIFOEJBObjectCache cache = new FIFOEJBObjectCache("UnitTestCache");
cache.init(512, 0, 0, (float)1.0, null);
int maxCount = 14;
ArrayList keys = new ArrayList();
for (int i=0; i
© 2015 - 2024 Weber Informatics LLC | Privacy Policy