001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.datacache;
020:
021: import org.apache.openjpa.event.RemoteCommitListener;
022: import org.apache.openjpa.lib.util.Localizer;
023: import org.apache.openjpa.util.CacheMap;
024:
025: /**
026: * A {@link DataCache} implementation that is optimized for concurrent
027: * access. When the cache fills up, values to remove from cache are chosen
028: * randomly. Due to race conditions, it is possible that a get call might not
029: * return a cached instance if that instance is being transferred between
030: * internal datastructures.
031: *
032: * @since 0.4.0
033: */
034: public class ConcurrentDataCache extends AbstractDataCache implements
035: RemoteCommitListener {
036:
037: private static final Localizer _loc = Localizer
038: .forPackage(ConcurrentDataCache.class);
039:
040: private final CacheMap _cache = newCacheMap();
041:
042: /**
043: * Returns the underlying {@link CacheMap} that this cache is using.
044: * This is not an unmodifiable view on the map, so care should be taken
045: * with this reference. Implementations should probably not modify the
046: * contents of the cache, but should only use this reference to
047: * obtain cache metrics.
048: */
049: public CacheMap getCacheMap() {
050: return _cache;
051: }
052:
053: /**
054: * Sets the maximum number of unpinned objects to keep hard
055: * references to. If the map contains more unpinned objects than
056: * <code>size</code>, then this method will result in the cache
057: * flushing old values.
058: */
059: public void setCacheSize(int size) {
060: _cache.setCacheSize(size);
061: }
062:
063: /**
064: * Returns the maximum number of unpinned objects to keep hard
065: * references to.
066: */
067: public int getCacheSize() {
068: return _cache.getCacheSize();
069: }
070:
071: /**
072: * Sets the maximum number of unpinned objects to keep soft
073: * references to. If the map contains more soft references than
074: * <code>size</code>, then this method will result in the cache
075: * flushing values.
076: */
077: public void setSoftReferenceSize(int size) {
078: _cache.setSoftReferenceSize(size);
079: }
080:
081: /**
082: * Returns the maximum number of unpinned objects to keep soft
083: * references to. Defaults to <code>-1</code>.
084: */
085: public int getSoftReferenceSize() {
086: return _cache.getSoftReferenceSize();
087: }
088:
089: public void initialize(DataCacheManager mgr) {
090: super .initialize(mgr);
091: conf.getRemoteCommitEventManager().addInternalListener(this );
092: }
093:
094: public void unpinAll(Class cls, boolean subs) {
095: if (log.isWarnEnabled())
096: log.warn(_loc.get("cache-class-unpin-all", getName()));
097: unpinAll(_cache.getPinnedKeys());
098: }
099:
100: public void writeLock() {
101: _cache.writeLock();
102: }
103:
104: public void writeUnlock() {
105: _cache.writeUnlock();
106: }
107:
108: /**
109: * Return the map to use as an internal cache; entry expirations must
110: * invoke {@link AbstractDataCache#keyRemoved}.
111: */
112: protected CacheMap newCacheMap() {
113: return new CacheMap() {
114: protected void entryRemoved(Object key, Object value,
115: boolean expired) {
116: keyRemoved(key, expired);
117: }
118: };
119: }
120:
121: protected DataCachePCData getInternal(Object key) {
122: return (DataCachePCData) _cache.get(key);
123: }
124:
125: protected DataCachePCData putInternal(Object key, DataCachePCData pc) {
126: return (DataCachePCData) _cache.put(key, pc);
127: }
128:
129: protected DataCachePCData removeInternal(Object key) {
130: return (DataCachePCData) _cache.remove(key);
131: }
132:
133: protected void removeAllInternal(Class cls, boolean subs) {
134: // we could keep a histogram of the counts of contained classes and
135: // only clear if we have the class, but that still wouldn't support subs
136: // well, would involve synching, and won't yield much benefit when we're
137: // used as a primary cache
138: _cache.clear();
139: }
140:
141: protected void clearInternal() {
142: _cache.clear();
143: }
144:
145: protected boolean pinInternal(Object key) {
146: return _cache.pin(key);
147: }
148:
149: protected boolean unpinInternal(Object key) {
150: return _cache.unpin(key);
151: }
152: }
|