/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.server.distcache;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import com.caucho.cloud.topology.TriadOwner;
import com.caucho.distcache.ExtCacheEntry;
import com.caucho.util.Alarm;
import com.caucho.util.HashKey;
import com.caucho.util.Hex;
/**
* An entry in the cache map
*/
public class DistCacheEntry implements ExtCacheEntry {
private final CacheStoreManager _cacheService;
private final HashKey _keyHash;
private final TriadOwner _owner;
private Object _key;
private final AtomicBoolean _isReadUpdate = new AtomicBoolean();
private final AtomicReference<MnodeEntry> _mnodeEntry
= new AtomicReference<MnodeEntry>(MnodeEntry.NULL);
private final AtomicInteger _loadCount = new AtomicInteger();
public DistCacheEntry(CacheStoreManager engine,
Object key,
HashKey keyHash,
TriadOwner owner)
{
_cacheService = engine;
_key = key;
_keyHash = keyHash;
_owner = owner;
}
public DistCacheEntry(CacheStoreManager engine,
Object key,
HashKey keyHash,
TriadOwner owner,
CacheConfig config)
{
_cacheService = engine;
_key = key;
_keyHash = keyHash;
_owner = owner;
}
/**
* Returns the key for this entry in the Cache.
*/
@Override
public final Object getKey()
{
return _key;
}
/**
* Returns the keyHash
*/
@Override
public final HashKey getKeyHash()
{
return _keyHash;
}
/**
* Returns the value of the cache entry.
*/
@Override
public Object getValue()
{
return getMnodeEntry().getValue();
}
/**
* Returns true if the value is null.
*/
@Override
public boolean isValueNull()
{
return getMnodeEntry().isValueNull();
}
/**
* Returns the cacheHash
*/
public final HashKey getCacheHash()
{
return getMnodeEntry().getCacheHashKey();
}
public final int getUserFlags()
{
return getMnodeEntry().getUserFlags();
}
/**
* Returns the owner
*/
public final TriadOwner getOwner()
{
return _owner;
}
/**
* Returns the value section of the entry.
*/
public final MnodeEntry getMnodeEntry()
{
return _mnodeEntry.get();
}
/**
* Peeks the current value without checking the backing store.
*/
public Object peek()
{
MnodeEntry entry = getMnodeEntry();
if (entry != null)
return entry.getValue();
else
return null;
}
/**
* Returns the object for the given key, checking the backing if necessary.
* If it is not found, the optional cacheLoader is invoked, if present.
*/
public Object get(CacheConfig config)
{
long now = Alarm.getCurrentTime();
return _cacheService.get(this, config, now);
}
/**
* Returns the object for the given key, checking the backing if necessary
*/
public MnodeEntry getMnodeValue(CacheConfig config)
{
long now = Alarm.getCurrentTime();
return _cacheService.getMnodeValue(this, config, now); // , false);
}
/**
* Fills the value with a stream
*/
public boolean getStream(OutputStream os, CacheConfig config)
throws IOException
{
return _cacheService.getStream(this, os, config);
}
public HashKey getValueHash(Object value, CacheConfig config)
{
return _cacheService.getValueHash(value, config).getValue();
}
/**
* Sets the current value
*/
public void put(Object value, CacheConfig config)
{
_cacheService.put(this, value, config);
}
/**
* Sets the value by an input stream
*/
public ExtCacheEntry put(InputStream is,
CacheConfig config,
long accessedExpireTimeout,
long modifiedExpireTimeout)
throws IOException
{
return _cacheService.putStream(this, is, config,
accessedExpireTimeout,
modifiedExpireTimeout,
0);
}
/**
* Sets the value by an input stream
*/
public ExtCacheEntry put(InputStream is,
CacheConfig config,
long accessedExpireTimeout,
long modifiedExpireTimeout,
int flags)
throws IOException
{
return _cacheService.putStream(this, is, config,
accessedExpireTimeout,
modifiedExpireTimeout,
flags);
}
/**
* Sets the current value
*/
public Object getAndPut(Object value, CacheConfig config)
{
return _cacheService.getAndPut(this, value, config);
}
/**
* Sets the current value
*/
public HashKey compareAndPut(HashKey testValue,
Object value,
CacheConfig config)
{
return _cacheService.compareAndPut(this, testValue, value, config);
}
/**
* Sets the current value
*/
public boolean compareAndPut(long version,
HashKey value,
long valueLength,
CacheConfig config)
{
return _cacheService.compareAndPut(this, version, value, valueLength, config);
}
/**
* Remove the value
*/
public boolean remove(CacheConfig config)
{
return _cacheService.remove(this, config);
}
/**
* Conditionally starts an update of a cache item, allowing only a
* single thread to update the data.
*
* @return true if the thread is allowed to update
*/
public final boolean startReadUpdate()
{
return _isReadUpdate.compareAndSet(false, true);
}
/**
* Completes an update of a cache item.
*/
public final void finishReadUpdate()
{
_isReadUpdate.set(false);
}
/**
* Sets the current value.
*/
public final boolean compareAndSet(MnodeEntry oldMnodeValue,
MnodeEntry mnodeValue)
{
return _mnodeEntry.compareAndSet(oldMnodeValue, mnodeValue);
}
@Override
public HashKey getValueHashKey()
{
MnodeEntry entry = getMnodeEntry();
if (entry != null)
return entry.getValueHashKey();
else
return null;
}
public byte []getValueHashArray()
{
return getMnodeEntry().getValueHash();
}
@Override
public long getValueLength()
{
return getMnodeEntry().getValueLength();
}
@Override
public long getAccessedExpireTimeout()
{
return getMnodeEntry().getAccessedExpireTimeout();
}
@Override
public long getModifiedExpireTimeout()
{
return getMnodeEntry().getModifiedExpireTimeout();
}
@Override
public boolean isExpired(long now)
{
MnodeEntry entry = getMnodeEntry();
if (entry != null)
return entry.isExpired(now);
else
return false;
}
@Override
public long getLeaseTimeout()
{
return getMnodeEntry().getLeaseTimeout();
}
@Override
public int getLeaseOwner()
{
return getMnodeEntry().getLeaseOwner();
}
public void clearLease()
{
MnodeEntry mnodeValue = getMnodeEntry();
if (mnodeValue != null)
mnodeValue.clearLease();
}
public long getCost()
{
return 0;
}
public long getCreationTime()
{
return getMnodeEntry().getCreationTime();
}
public long getExpirationTime()
{
return getMnodeEntry().getExpirationTime();
}
public int getHits()
{
return getMnodeEntry().getHits();
}
public long getLastAccessedTime()
{
return getMnodeEntry().getLastAccessedTime();
}
public long getLastModifiedTime()
{
return getMnodeEntry().getLastModifiedTime();
}
public long getVersion()
{
MnodeEntry entry = getMnodeEntry();
if (entry != null)
return entry.getVersion();
else
return 0;
}
public boolean isValid()
{
return getMnodeEntry().isValid();
}
public Object setValue(Object value)
{
return getMnodeEntry().setValue(value);
}
//
// statistics
//
public void addLoadCount()
{
_loadCount.incrementAndGet();
}
@Override
public int getLoadCount()
{
return _loadCount.get();
}
@Override
public String toString()
{
return (getClass().getSimpleName()
+ "[key=" + _key
+ ",keyHash=" + Hex.toHex(_keyHash.getHash(), 0, 4)
+ ",owner=" + _owner
+ "]");
}
}