|
Glassfish example source code file (LruSessionCache.java)
The Glassfish LruSessionCache.java source code/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 1997-2010 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 com.sun.ejb.containers.util.cache; import com.sun.appserv.util.cache.CacheListener; import com.sun.ejb.base.io.IOUtils; import com.sun.ejb.spi.container.SFSBContainerCallback; import com.sun.ejb.spi.container.StatefulEJBContext; import com.sun.ejb.base.stats.StatefulSessionStoreMonitor; import org.glassfish.ha.store.api.BackingStore; import org.glassfish.ha.store.util.SimpleMetadata; import org.glassfish.ha.store.api.BackingStoreException; import java.io.Serializable; import java.util.*; import java.util.logging.*; public class LruSessionCache extends LruCache implements com.sun.ejb.spi.stats.EJBCacheStatsProvider { protected int numActivated; protected int cacheIdleTimeoutInSeconds; protected int removalTimeoutInSeconds; protected Object loadCountLock = new Object(); protected int loadFromBackupCount; protected boolean removeIfIdle = false; public int passivationCount = 0; protected Object passivationCountLock = new Object(); private Object numPassLock = new Object(); private int numVictimsAccessed = 0; protected SFSBContainerCallback container; protected BackingStore<Serializable, SimpleMetadata> backingStore; private static final byte CACHE_ITEM_VALID = 0; private static final byte CACHE_ITEM_LOADING = 1; private static final byte CACHE_ITEM_REMOVED = 2; protected String configData; private static final int STATE_RUNNING = 0; private static final int STATE_SHUTTING_DOWN = 1; private static final int STATE_UNDEPLOYING = 2; private static final int STATE_DESTROYED = 3; private int currentCacheState = STATE_RUNNING; protected int confMaxCacheSize = Integer.MAX_VALUE; // TODO enable when enabling monitoring in SFSB container // private StatefulSessionStoreMonitor sfsbStoreMonitor; /** * Destroys all references. This is the last method call of this object's * life cycle. * * This method is called during undeploy of ejb container. */ public void destroy() { this.currentCacheState = STATE_DESTROYED; this.container = null; super.destroy(); } public LruSessionCache(String cacheName, SFSBContainerCallback container, int cacheIdleTime, int removalTime) { super(); super.setCacheName(cacheName); this.container = container; this.cacheIdleTimeoutInSeconds = (cacheIdleTime <= 0) ? 0 : cacheIdleTime; this.removalTimeoutInSeconds = (removalTime <= 0) ? 0 : removalTime; if (cacheIdleTimeoutInSeconds > 0) { super.timeout = cacheIdleTimeoutInSeconds*1000L; } removeIfIdle = (removalTimeoutInSeconds > 0) && (removalTimeoutInSeconds <= cacheIdleTimeoutInSeconds); } public void setBackingStore(BackingStore<Serializable, SimpleMetadata> store) { this.backingStore = store; } public void setStatefulSessionStoreMonitor( StatefulSessionStoreMonitor storeMonitor) { // this.sfsbStoreMonitor = storeMonitor; } /** * trim the item from the cache and notify listeners * @param item to be trimmed */ protected void trimItem(CacheItem item) { LruCacheItem removed = (LruCacheItem) item; if (removeIfIdle) { StatefulEJBContext ctx = (StatefulEJBContext) item.value; long idleThreshold = System.currentTimeMillis() - removalTimeoutInSeconds*1000L; if (ctx.getLastAccessTime() <= idleThreshold) { container.passivateEJB(ctx); return; } } for (int i = 0; i < listeners.size(); i++) { CacheListener listener = (CacheListener) listeners.get(i); listener.trimEvent(removed.key, removed.value); } } protected void itemAccessed(CacheItem item) { LruCacheItem lc = (LruCacheItem) item; synchronized (this) { if (lc.isTrimmed) { lc.isTrimmed = false; numVictimsAccessed += 1; CacheItem overflow = super.itemAdded(item); if (overflow != null) { trimItem(overflow); } } else { super.itemAccessed(item); } } } public int getLoadFromBackupCount() { return loadFromBackupCount; } protected void incrementLoadFromBackupCount() { synchronized (loadCountLock) { loadFromBackupCount++; } } // return the EJB for the given instance key //Called from StatefulSessionContainer public StatefulEJBContext lookupEJB(Serializable sessionKey, SFSBContainerCallback container, Object cookie) { int hashCode = hash(sessionKey); int index = getIndex(hashCode); CacheItem item = null; LruSessionCacheItem newItem = null; Object value = null; synchronized (bucketLocks[index]) { item = buckets[index]; for (; item != null; item = item.next) { if ( (hashCode == item.hashCode) && (item.key.equals(sessionKey)) ) { value = item.value; break; } } // update the stats in line if (value != null) { itemAccessed(item); } else if (item == null) { newItem = new LruSessionCacheItem(hashCode, sessionKey, null, -1, CACHE_ITEM_LOADING); newItem.next = buckets[index]; buckets[index] = newItem; } } if (value != null) { incrementHitCount(); return (StatefulEJBContext) value; } incrementMissCount(); if (item != null) { synchronized (item) { LruSessionCacheItem lruItem = (LruSessionCacheItem) item; if ((lruItem.value == null) && (lruItem.cacheItemState == CACHE_ITEM_LOADING)) { lruItem.waitCount++; try { item.wait(); } catch (InterruptedException inEx) {} } return (StatefulEJBContext) item.value; } } //This is the thread that actually does the I/O long activationStartTime = -1; /*if (sfsbStoreMonitor.isMonitoringOn()) { activationStartTime = System.currentTimeMillis(); }*/ try { newItem.value = value = getStateFromStore(sessionKey, container); synchronized (buckets[index]) { if (value == null) { //Remove the temp cacheItem that we created. CacheItem prev = null; for (CacheItem current = buckets[index]; current != null; current = current.next) { if (current == newItem) { if (prev == null) { buckets[index] = current.next; } else { prev.next = current.next; } current.next = null; break; } prev = current; } } else { container.activateEJB(sessionKey, (StatefulEJBContext) value, cookie); // sfsbStoreMonitor.incrementActivationCount(true); CacheItem overflow = itemAdded(newItem); incrementEntryCount(); // make sure we are are not crossing the threshold if (overflow != null) { trimItem(overflow); } } } //end of sync } catch (javax.ejb.EJBException ejbEx) { //sfsbStoreMonitor.incrementActivationCount(false); remove(sessionKey); value = null; } finally { synchronized (newItem) { newItem.cacheItemState = CACHE_ITEM_VALID; if (newItem.waitCount > 0) { newItem.notifyAll(); } } if (activationStartTime != -1) { long timeSpent = System.currentTimeMillis() - activationStartTime; //sfsbStoreMonitor.setActivationTime(timeSpent); } } return (StatefulEJBContext) value; } //Called from StatefulSessionContainer //public void deleteEJB(Object sessionKey) public Object remove(Object sessionKey) { return remove(sessionKey, true); } public Object remove(Object sessionKey, boolean removeFromStore) { int hashCode = hash(sessionKey); int index = getIndex(hashCode); CacheItem prev = null, item = null; synchronized (bucketLocks[index]) { for (item = buckets[index]; item != null; item = item.next) { if ((hashCode == item.hashCode) && sessionKey.equals(item.key)) { if (prev == null) { buckets[index] = item.next; } else { prev.next = item.next; } item.next = null; itemRemoved(item); ((LruSessionCacheItem) item).cacheItemState = CACHE_ITEM_REMOVED; break; } prev = item; } //remove it from the BackingStore also //In case it had been checkpointed // remove it from BackingStore outside sync block if (removeFromStore) { try { backingStore.remove((Serializable) sessionKey); } catch (BackingStoreException sfsbEx) { _logger.log(Level.WARNING, "[" + cacheName + "]: Exception in " + "backingStore.remove(" + sessionKey + ")", sfsbEx); } } } if (item != null) { decrementEntryCount(); incrementRemovalCount(); incrementHitCount(); } else { incrementMissCount(); } return null; } // Called by Cache implementation thru container, on Recycler's thread // The container has already acquired the lock on the StatefulEJBContext public boolean passivateEJB(StatefulEJBContext ctx, Serializable sessionKey) throws java.io.NotSerializableException { try { int hashCode = hash(sessionKey); int index = getIndex(hashCode); boolean itemRemoved = false; CacheItem prev = null, item = null; synchronized (bucketLocks[index]) { for (item = buckets[index]; item != null; item = item.next) { if (item.value == ctx) { LruCacheItem lruSCItem = (LruCacheItem) item; if (lruSCItem.isTrimmed == false) { //Was accessed just after marked for passivation if(_logger.isLoggable(Level.FINE)) { _logger.log(Level.FINE, cacheName + ": session accessed after marked for passivation: " + sessionKey); } return false; } break; } prev = item; } if (item == null) { //Could have been removed return true; //??????? } if (removeIfIdle) { long idleThreshold = System.currentTimeMillis() - removalTimeoutInSeconds*1000L; //XXX: Avoid currentTimeMillis if (ctx.getLastAccessTime() <= idleThreshold) { if(_logger.isLoggable(Level.FINE)) { _logger.log(Level.FINE, cacheName + ": Removing session " + " instead of passivating for key: " + sessionKey); } if (prev == null) { buckets[index] = item.next; } else { prev.next = item.next; } item.next = null; itemRemoved = true; //TODO::store.incrementExpiredSessionsRemoved(); } } } if (itemRemoved) { decrementEntryCount(); incrementRemovalCount(); return true; } if (saveStateToStore(sessionKey, ctx) == false) { return false; } synchronized (bucketLocks[index]) { prev = null; for (item = buckets[index]; item != null; item = item.next) { if (item.value == ctx) { LruCacheItem lruSCItem = (LruCacheItem) item; if (lruSCItem.isTrimmed == false) { //Was accessed just after marked for passivation return false; } if (prev == null) { buckets[index] = item.next; } else { prev.next = item.next; } item.next = null; break; } prev = item; } } if (item != null) { decrementEntryCount(); incrementRemovalCount(); } return true; } catch (java.io.NotSerializableException notSerEx) { throw notSerEx; } catch (Exception ex) { _logger.log(Level.WARNING, "[" + cacheName + "]: passivateEJB(), Exception caught -> ",ex); } return false; } //passivateEJB private Object getStateFromStore(Serializable sessionKey, SFSBContainerCallback container) { Object object = null; try { SimpleMetadata beanState = backingStore.load(sessionKey, null); byte[] data = (beanState != null) ? beanState.getState() : null; if ( data == null ) { if(_logger.isLoggable(Level.SEVERE)) { _logger.log(Level.SEVERE, cacheName + ": Cannot load from " + " BACKUPSTORE FOR Key: <" + sessionKey + ">"); } } else { //sfsbStoreMonitor.setActivationSize(data.length); incrementLoadFromBackupCount(); object = IOUtils.deserializeObject(data, true, container.getClassLoader()); } } catch ( Exception ex ) { _logger.log(Level.SEVERE, cacheName + ": Exception while " + " loading from backup session: <" + sessionKey + ">", ex); } catch ( Error ex ) { _logger.log(Level.SEVERE, cacheName + ": Error while " + " loading from backup session: <" + sessionKey + ">", ex); } return object; } private boolean saveStateToStore(Serializable sessionKey, StatefulEJBContext ctx) throws java.io.NotSerializableException, java.io.IOException { byte[] data = IOUtils.serializeObject(ctx.getSessionContext(), true); //If we are here then we were able to serialize the object successfully boolean status = false; if (data != null) { SimpleMetadata beanState = new SimpleMetadata( ctx.getVersion(), ctx.getLastAccessTime(), removalTimeoutInSeconds*1000, data); //Note: Don't increment the version here because // this is called on an async thread and the client // already has the correct version beanState.setVersion(ctx.getVersion()); try { backingStore.save(sessionKey, beanState, !ctx.existsInStore()); // sfsbStoreMonitor.setPassivationSize(data.length); status = true; } catch (BackingStoreException sfsbEx) { _logger.log(Level.WARNING, "[" + cacheName + "]: Exception during " + "backingStore.passivateSave(" + sessionKey + ")", sfsbEx); } } return status; } private void trimSelectedVictims(ArrayList victims) { int sz = victims.size(); synchronized (this) { trimCount += sz; } CacheItem item = null; for (int i=0; i<sz; i++) { item = (CacheItem) victims.get(i); trimItem(item); } } public void setShutdownState() { currentCacheState = STATE_SHUTTING_DOWN; } public void setUndeployedState() { currentCacheState = STATE_UNDEPLOYING; } /** * get an Iterator for the values stored in the cache * @returns an Iterator */ public Iterator values() { ArrayList valueList = new ArrayList(); synchronized (this) { LruCacheItem item = tail; while (item != null) { StatefulEJBContext ctx = (StatefulEJBContext) item.value; if (ctx != null) { valueList.add(ctx); } //Ensure that for head the lPrev is null if( (item == head) && (item.lPrev != null) ) { _logger.log(Level.WARNING, "[" + cacheName + "]: Iterator(), resetting head.lPrev"); item.lPrev = null; } // traverse to the previous one item = item.lPrev; } } return valueList.iterator(); } public void shutdown() { ArrayList<StatefulEJBContext> valueList = new ArrayList Other Glassfish examples (source code examples)Here is a short list of links related to this Glassfish LruSessionCache.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.