/** Merge the transactional caches into the shared cache */ public void beforeCommit(boolean readOnly) { if (isDebugEnabled) { logger.debug("Processing before-commit"); } TransactionData txnData = getTransactionData(); try { if (txnData.isClearOn) { // clear shared cache final long startNanos = cacheStatsEnabled ? System.nanoTime() : 0; sharedCache.clear(); final long endNanos = cacheStatsEnabled ? System.nanoTime() : 0; if (cacheStatsEnabled) { TransactionStats stats = txnData.stats; stats.record(startNanos, endNanos, OpType.CLEAR); } if (isDebugEnabled) { logger.debug("Clear notification recieved in commit - clearing shared cache"); } } else { // transfer any removed items for (Serializable key : txnData.removedItemsCache) { final long startNanos = System.nanoTime(); sharedCache.remove(key); final long endNanos = System.nanoTime(); TransactionStats stats = txnData.stats; stats.record(startNanos, endNanos, OpType.REMOVE); } if (isDebugEnabled) { logger.debug( "Removed " + txnData.removedItemsCache.size() + " values from shared cache in commit"); } } // transfer updates Set<Serializable> keys = (Set<Serializable>) txnData.updatedItemsCache.keySet(); for (Map.Entry<Serializable, CacheBucket<V>> entry : (Set<Map.Entry<Serializable, CacheBucket<V>>>) txnData.updatedItemsCache.entrySet()) { Serializable key = entry.getKey(); CacheBucket<V> bucket = entry.getValue(); bucket.doPreCommit( sharedCache, key, this.isMutable, this.allowEqualsChecks, txnData.isReadOnly); } if (isDebugEnabled) { logger.debug("Pre-commit called for " + keys.size() + " values."); } } catch (Throwable e) { throw new AlfrescoRuntimeException("Failed to transfer updates to shared cache", e); } finally { // Block any further updates txnData.isClosed = true; } }
/** Merge the transactional caches into the shared cache */ public void afterCommit() { if (isDebugEnabled) { logger.debug("Processing after-commit"); } TransactionData txnData = getTransactionData(); try { if (txnData.isClearOn) { // clear shared cache final long startNanos = cacheStatsEnabled ? System.nanoTime() : 0; sharedCache.clear(); final long endNanos = cacheStatsEnabled ? System.nanoTime() : 0; if (cacheStatsEnabled) { TransactionStats stats = txnData.stats; stats.record(startNanos, endNanos, OpType.CLEAR); } if (isDebugEnabled) { logger.debug("Clear notification recieved in commit - clearing shared cache"); } } else { // transfer any removed items for (Serializable key : txnData.removedItemsCache) { final long startNanos = System.nanoTime(); sharedCache.remove(key); final long endNanos = System.nanoTime(); TransactionStats stats = txnData.stats; stats.record(startNanos, endNanos, OpType.REMOVE); } if (isDebugEnabled) { logger.debug( "Removed " + txnData.removedItemsCache.size() + " values from shared cache in commit"); } } // transfer updates Set<Serializable> keys = (Set<Serializable>) txnData.updatedItemsCache.keySet(); for (Map.Entry<Serializable, CacheBucket<V>> entry : (Set<Map.Entry<Serializable, CacheBucket<V>>>) txnData.updatedItemsCache.entrySet()) { Serializable key = entry.getKey(); CacheBucket<V> bucket = entry.getValue(); try { bucket.doPostCommit( sharedCache, key, this.isMutable, this.allowEqualsChecks, txnData.isReadOnly, txnData.stats); } catch (Exception e) { // MNT-10486: NPE in NodeEntity during post-commit write through to shared cache // This try-catch is diagnostic in nature. We need to know the names of the // caches // and details of the values involved. // The causal exception will be rethrown. throw new AlfrescoRuntimeException( "CacheBucket postCommit transfer to shared cache failed: \n" + " Cache: " + sharedCache + "\n" + " Key: " + key + "\n" + " New Value: " + bucket.getValue() + "\n" + " Cache Value:" + sharedCache.get(key), e); } } if (isDebugEnabled) { logger.debug("Post-commit called for " + keys.size() + " values."); } } catch (Throwable e) { throw new AlfrescoRuntimeException("Failed to transfer updates to shared cache", e); } finally { removeCaches(txnData); // Aggregate this transaction's stats with centralised cache stats. if (cacheStatsEnabled) { cacheStats.add(name, txnData.stats); } } }
/** * Checks the per-transaction caches for the object before going to the shared cache. If the * thread is not in a transaction, then the shared cache is accessed directly. */ public V get(K keyIn) { final Serializable key = getTenantAwareCacheKey(keyIn); boolean ignoreSharedCache = false; // are we in a transaction? if (AlfrescoTransactionSupport.getTransactionId() != null) { TransactionData txnData = getTransactionData(); if (txnData.isClosed) { // This check could have been done in the first if block, but that would have added another // call to the // txn resources. } else // The txn is still active { 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)) { // 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 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 if (txnData.noSharedCacheRead) { // Explicitly told to ignore shared cache ignoreSharedCache = true; } else { // There is no in-txn entry for the key // Use the value direct from the shared cache V value = null; if (cacheStatsEnabled) { value = TransactionalCache.getSharedCacheValue(sharedCache, key, txnData.stats); } else { // No stats tracking, pass in null TransactionStats value = TransactionalCache.getSharedCacheValue(sharedCache, key, null); } bucket = new ReadCacheBucket<V>(value); txnData.updatedItemsCache.put(key, bucket); return value; } } } // no value found - must we ignore the shared cache? if (!ignoreSharedCache) { V value = TransactionalCache.getSharedCacheValue(sharedCache, key, null); // go to the shared cache if (isDebugEnabled) { logger.debug( "No value found in transaction - fetching instance from shared cache: \n" + " cache: " + this + "\n" + " key: " + key + "\n" + " value: " + value); } return value; } else // ignore shared cache { if (isDebugEnabled) { logger.debug( "No value found in transaction and ignoring shared cache: \n" + " cache: " + this + "\n" + " key: " + key); } return null; } }