Derek Hulley 25382b991f Merged DEV to HEAD: Cache write optimizations
- Refix ALF-10665: Caches that use @@VALUE_NOT_FOUND@@ are not really immutable
 - Add NodeBulkLoader.setCheckNodeConsistency
   - Use in a transaction to ensure that the node cache views are consistent with
     the database views.
 - Increase size of contentDataCache and make it support equals checking
 - Details:
   32162: Read-through cache changes
   32163: TransactionalCache changes to support more efficient consistency guarantees
          - 'allowEqualsCheck' property allows cache to do a full equals check against changed shared cache values
          - In-transaction option 'setDisableSharedCacheReadForTransaction'.  Values are cache in-transaction
            and written back at the end of the transaction (subject to collision rules) but the first read will
            not go to the shared cache.
          - Drop optimistic write-through in read-only transactions; they are equally likely to want to flush
            stale data.
          - Add simpler logic for mutable and allowEqualsCheck and make sure all conditions are covered by tests
   32164: Cache node entity support TransactionalCache's allowEqualsCheck
   32165: Add NodeDAO.setCheckNodeConsistency() method
          - Allows code to request that node metadata is consistent with whatever view the DB is providing
          - Incorporate into node concurrency tests without issue
          - Only one cache is affected (nodesCache) and it is enhanced by having 'allowEqualsCheck' to prevent
            massive flushing when multiple read transactions are all trying to push data into the shared caches,
            particularly during (re)indexing operations.
          - Further reduces the cache invalidation messages required in order to maintain consistency across
            the cluster
   32166: Make Lucene reindex work (trackers and FTS) use enforced node consistency
          - bulkLoader.setCheckNodeConsistency() incorporated where 'isReadThrough' is on
   32167: SOLR tracking uses NodeDAO.setCheckNodeConsistency() during node metadata retrieval
          - Ensures that any stale node metadata does not find its way into indexed SOLR node metadata
   32207: Fix ALF-11644: AVM cleanup jobs run when WCM is not installed
          - Moved scheduled jobs to installable wcm-bootstrap-context.xml
          - Also got rid of orphan reaper warnings when running in a cluster
   32208: Better hashcode for NodeVersionKey
   32209: RECORD ONLY
   32210: RECORD ONLY
   32212: Proper fix for ALF-10665: Immutable caches do not respond well to null (=> @@VALUE_NOT_FOUND@@)
          - The following caches were incorrectly classed as 'immutable':
               propertyValueCache
               immutableEntityCache
               rootNodesCache
               allRootNodesCache
               authorityCache
               tagscopeSummaryCache
               imapMessageCache
          - The 'immutable' caches are:
               node.aspectsCache
               node.propertiesCache
               node.parentAssocsCache
          - The following caches support equals checks:
               node.nodesCache
               authorityLookupCache
   32213: Fixed getNodeRefStatus(): nodesCache caches deleted entries as well.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@32657 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2011-12-08 23:51:36 +00:00

310 lines
7.7 KiB
Java

/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.domain.node;
import org.alfresco.repo.security.permissions.PermissionCheckValue;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.Pair;
/**
* Bean to convey <b>alf_node</b> data.
*
* @author Derek Hulley
* @since 3.4
*/
public class NodeEntity implements Node, PermissionCheckValue
{
private boolean locked;
private Long id;
private Long version;
private StoreEntity store;
private String uuid;
private Long typeQNameId;
private Long localeId;
private Long aclId;
private Boolean deleted;
private TransactionEntity transaction;
private AuditablePropertiesEntity auditableProperties;
/**
* Required default constructor
*/
public NodeEntity()
{
locked = false;
}
/**
* Helper constructor to build the necessary elements to fulfill the {@link #getNodeRef()} query
*/
/* package */ NodeEntity(NodeRef nodeRef)
{
this();
this.store = new StoreEntity();
this.store.setProtocol(nodeRef.getStoreRef().getProtocol());
this.store.setIdentifier(nodeRef.getStoreRef().getIdentifier());
this.uuid = nodeRef.getId();
}
/**
* Helper copy constructor
*/
/* package */ NodeEntity(Node node)
{
this.id = node.getId();
this.version = node.getVersion();
this.store = node.getStore();
this.uuid = node.getUuid();
this.typeQNameId = node.getTypeQNameId();
this.localeId = node.getLocaleId();
this.aclId = node.getAclId();
this.deleted = node.getDeleted();
this.transaction = node.getTransaction();
this.auditableProperties = node.getAuditableProperties();
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((version == null) ? 0 : version.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (obj == null) return false;
if (!(obj instanceof NodeEntity)) return false;
NodeEntity that = (NodeEntity) obj;
return this.id.equals(that.id) && this.version.equals(that.version);
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder(512);
sb.append("NodeEntity")
.append("[ ID=").append(id)
.append(", version=").append(version);
if (store != null)
{
sb.append(", store=").append(store.getProtocol()).append("://").append(store.getIdentifier());
}
else
{
sb.append(", store=").append("null");
}
sb.append(", uuid=").append(uuid)
.append(", typeQNameId=").append(typeQNameId)
.append(", localeId=").append(localeId)
.append(", aclId=").append(aclId)
.append(", deleted=").append(deleted)
.append(", transaction=").append(transaction)
.append(", auditProps=").append(auditableProperties)
.append("]");
return sb.toString();
}
@Override
// TODO: Must cache the key
public NodeVersionKey getNodeVersionKey()
{
if (id == null || version == null)
{
throw new IllegalStateException("The NodeEntity has not be filled: " + this);
}
return new NodeVersionKey(id, version);
}
/**
* Lock the entity against further updates to prevent accidental modification
*/
public synchronized void lock()
{
locked = true;
if (auditableProperties != null)
{
auditableProperties.lock();
}
}
private synchronized final void checkLock()
{
if (locked)
{
throw new IllegalStateException("The entity is locked against updates: " + this);
}
}
public synchronized void incrementVersion()
{
checkLock();
if (version >= Short.MAX_VALUE)
{
this.version = 0L;
}
else
{
this.version++;
}
}
@Override
public NodeRef getNodeRef()
{
return new NodeRef(store.getStoreRef(), uuid);
}
@Override
public NodeRef.Status getNodeStatus()
{
NodeRef nodeRef = new NodeRef(store.getStoreRef(), uuid);
return new NodeRef.Status(nodeRef, transaction.getChangeTxnId(), transaction.getId(), deleted);
}
@Override
public Pair<Long, NodeRef> getNodePair()
{
return new Pair<Long, NodeRef>(id, getNodeRef());
}
@Override
public Long getId()
{
return id;
}
public synchronized void setId(Long id)
{
checkLock();
this.id = id;
}
@Override
public Long getVersion()
{
return version;
}
public synchronized void setVersion(Long version)
{
checkLock();
this.version = version;
}
@Override
public StoreEntity getStore()
{
return store;
}
public synchronized void setStore(StoreEntity store)
{
checkLock();
this.store = store;
}
@Override
public String getUuid()
{
return uuid;
}
public synchronized void setUuid(String uuid)
{
checkLock();
this.uuid = uuid;
}
@Override
public Long getTypeQNameId()
{
return typeQNameId;
}
public synchronized void setTypeQNameId(Long typeQNameId)
{
checkLock();
this.typeQNameId = typeQNameId;
}
@Override
public Long getLocaleId()
{
return localeId;
}
public synchronized void setLocaleId(Long localeId)
{
this.localeId = localeId;
}
@Override
public Long getAclId()
{
return aclId;
}
public synchronized void setAclId(Long aclId)
{
checkLock();
this.aclId = aclId;
}
@Override
public Boolean getDeleted()
{
return deleted;
}
public synchronized void setDeleted(Boolean deleted)
{
checkLock();
this.deleted = deleted;
}
@Override
public TransactionEntity getTransaction()
{
return transaction;
}
public synchronized void setTransaction(TransactionEntity transaction)
{
checkLock();
this.transaction = transaction;
}
@Override
public AuditablePropertiesEntity getAuditableProperties()
{
return auditableProperties;
}
public synchronized void setAuditableProperties(AuditablePropertiesEntity auditableProperties)
{
checkLock();
this.auditableProperties = auditableProperties;
}
}