Merged DEV to HEAD

31651: Fixed up concurrency tests: target concurrent aspect adds in addition to numeric property increments
   31652: Ensure DB-based concurrency problems are propagated when updating alf_node (not just optimistic lock detections)
   31823: TransactionalCache provides REPEATABLE READ
          - Values found in shared cache are placed into transactional cache
          - Previously, values could keep changing until first write (READ COMMITTED)
            but now the first read sets the value until it is changed by the current
            transaction
   31825: Minor comment about node version rollover after version=32767
   31826: Immutable node caches: properties, aspects and parent assocs are immutable
          - cache entries are only put but never updated
          - zero cluster overhead for these 3 caches
          - Stale nodeCache detection when reading properties, aspects or parent assocs
          - Added tests to introspect on the caches directly to validate behaviour
          - Ensure that each node gets a single version increment per transaction
   31854: Cater for cm:auditable changes during touchNode()


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@31912 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2011-11-11 16:37:07 +00:00
parent cca70d44b8
commit ae202a3f24
8 changed files with 679 additions and 357 deletions

View File

@@ -311,43 +311,50 @@ public class TransactionalCache<K extends Serializable, V extends Object>
}
else // The txn is still active
{
try
if (!txnData.isClearOn) // deletions cache only useful before a clear
{
if (!txnData.isClearOn) // deletions cache only useful before a clear
// check to see if the key is present in the transaction's removed items
if (txnData.removedItemsCache.contains(key))
{
// check to see if the key is present in the transaction's removed items
if (txnData.removedItemsCache.contains(key))
{
// it has been removed in this transaction
if (isDebugEnabled)
{
logger.debug("get returning null - item has been removed from transactional cache: \n" +
" cache: " + this + "\n" +
" key: " + key);
}
return null;
}
}
// check for the item in the transaction's new/updated items
CacheBucket<V> bucket = (CacheBucket<V>) txnData.updatedItemsCache.get(key);
if (bucket != null)
{
V value = bucket.getValue();
// element was found in transaction-specific updates/additions
// it has been removed in this transaction
if (isDebugEnabled)
{
logger.debug("Found item in transactional cache: \n" +
logger.debug("get returning null - item has been removed from transactional cache: \n" +
" cache: " + this + "\n" +
" key: " + key + "\n" +
" value: " + value);
" key: " + key);
}
return value;
return null;
}
}
catch (CacheException e)
// check for the item in the transaction's new/updated items
CacheBucket<V> bucket = (CacheBucket<V>) txnData.updatedItemsCache.get(key);
if (bucket != null)
{
throw new AlfrescoRuntimeException("Cache failure", e);
V value = bucket.getValue();
// element was found in transaction-specific updates/additions
if (isDebugEnabled)
{
logger.debug("Found item in transactional cache: \n" +
" cache: " + this + "\n" +
" key: " + key + "\n" +
" value: " + value);
}
return value;
}
else if (txnData.isClearOn)
{
// Can't store values in the current txn any more
ignoreSharedCache = true;
}
else
{
// There is no in-txn entry for the key
// Use the value direct from the shared cache
V value = getSharedCacheValue(key);
bucket = new ReadCacheBucket<V>(value);
txnData.updatedItemsCache.put(key, bucket);
return value;
}
// check if the cleared flag has been set - cleared flag means ignore shared as unreliable
ignoreSharedCache = txnData.isClearOn;
@@ -929,6 +936,37 @@ public class TransactionalCache<K extends Serializable, V extends Object>
}
}
/**
* Data holder to represent data read from the shared cache. It will not attempt to
* update the shared cache.
*/
private static class ReadCacheBucket<BV> implements CacheBucket<BV>
{
private static final long serialVersionUID = 7885689778259779578L;
private final BV value;
public ReadCacheBucket(BV value)
{
this.value = value;
}
public BV getValue()
{
return value;
}
public void doPreCommit(
SimpleCache<Serializable, Object> sharedCache,
Serializable key,
boolean mutable, boolean readOnly)
{
}
public void doPostCommit(
SimpleCache<Serializable, Object> sharedCache,
Serializable key,
boolean mutable, boolean readOnly)
{
}
}
/** Data holder to bind data to the transaction */
private class TransactionData
{