blob: 8f051bc4aad7b4f18eedab6fdf97d3bc83c5538c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.geode.internal.cache;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.geode.annotations.Immutable;
import org.apache.geode.cache.CacheWriter;
import org.apache.geode.cache.CacheWriterException;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.EntryEvent;
import org.apache.geode.cache.EntryNotFoundException;
import org.apache.geode.cache.Operation;
import org.apache.geode.cache.TimeoutException;
import org.apache.geode.cache.TransactionId;
import org.apache.geode.distributed.internal.DistributionManager;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.internal.ByteArrayDataInput;
import org.apache.geode.internal.InternalStatisticsDisabledException;
import org.apache.geode.internal.Version;
import org.apache.geode.internal.cache.InitialImageOperation.Entry;
import org.apache.geode.internal.cache.entries.DiskEntry;
import org.apache.geode.internal.cache.eviction.EvictionList;
import org.apache.geode.internal.cache.tier.sockets.ClientProxyMembershipID;
import org.apache.geode.internal.cache.versions.RegionVersionVector;
import org.apache.geode.internal.cache.versions.VersionHolder;
import org.apache.geode.internal.cache.versions.VersionSource;
import org.apache.geode.internal.cache.versions.VersionStamp;
import org.apache.geode.internal.cache.versions.VersionTag;
import org.apache.geode.internal.offheap.annotations.Released;
import org.apache.geode.internal.util.concurrent.ConcurrentMapWithReusableEntries;
/**
* Internal implementation of {@link RegionMap}for regions whose DataPolicy is proxy. Proxy maps are
* always empty.
*
* @since GemFire 5.0
*/
class ProxyRegionMap extends BaseRegionMap {
private final TxCallbackEventFactory txCallbackEventFactory = new TxCallbackEventFactoryImpl();
protected ProxyRegionMap(LocalRegion owner, Attributes attr,
InternalRegionArguments internalRegionArgs) {
this.owner = owner;
this.attr = attr;
}
/**
* the region that owns this map
*/
private final LocalRegion owner;
private final Attributes attr;
@Override
public RegionEntryFactory getEntryFactory() {
throw new UnsupportedOperationException();
}
@Override
public Attributes getAttributes() {
return this.attr;
}
@Override
public void changeOwner(LocalRegion r) {
throw new UnsupportedOperationException();
}
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public Set keySet() {
return Collections.emptySet();
}
@Override
public Collection<RegionEntry> regionEntries() {
return Collections.emptySet();
}
@Override
public Collection<RegionEntry> regionEntriesInVM() {
return Collections.emptySet();
}
@Override
public boolean containsKey(Object key) {
return false;
}
@Override
public RegionEntry getEntry(Object key) {
return null;
}
@Override
public RegionEntry putEntryIfAbsent(Object key, RegionEntry re) {
return null;
}
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public Set<VersionSource> clear(RegionVersionVector rvv, BucketRegion bucketRegion) {
// nothing needs to be done
RegionVersionVector v = this.owner.getVersionVector();
if (v != null) {
return v.getDepartedMembersSet();
} else {
return Collections.emptySet();
}
}
public void diskClear() {
// nothing needs to be done
}
@Override
public RegionEntry initRecoveredEntry(Object key, DiskEntry.RecoveredEntry value) {
throw new UnsupportedOperationException();
}
@Override
public RegionEntry updateRecoveredEntry(Object key, DiskEntry.RecoveredEntry value) {
throw new UnsupportedOperationException();
}
/**
* Used to modify an existing RegionEntry or create a new one when processing the values obtained
* during a getInitialImage.
*/
@Override
public boolean initialImagePut(Object key, long lastModified, Object newValue,
boolean wasRecovered, boolean deferLRUCallback, VersionTag entryVersion,
InternalDistributedMember sender, boolean forceValue) {
throw new UnsupportedOperationException();
}
@Override
public boolean destroy(EntryEventImpl event, boolean inTokenMode, boolean duringRI,
boolean cacheWrite, boolean isEviction, Object expectedOldValue, boolean removeRecoveredEntry)
throws CacheWriterException, EntryNotFoundException, TimeoutException {
if (event.getOperation().isLocal()) {
throw new EntryNotFoundException(event.getKey().toString());
}
if (cacheWrite) {
this.owner.cacheWriteBeforeDestroy(event, expectedOldValue);
}
owner.recordEvent(event);
this.owner.basicDestroyPart2(markerEntry, event, inTokenMode,
false /* Clear conflict occurred */, duringRI, true);
this.owner.basicDestroyPart3(markerEntry, event, inTokenMode, duringRI, true, expectedOldValue);
return true;
}
@Override
public boolean invalidate(EntryEventImpl event, boolean invokeCallbacks, boolean forceNewEntry,
boolean forceCallbacks) throws EntryNotFoundException {
if (event.getOperation().isLocal()) {
if (this.owner.isInitialized()) {
forceInvalidateEvent(event, this.owner);
}
throw new EntryNotFoundException(event.getKey().toString());
}
this.owner.serverInvalidate(event);
this.owner.recordEvent(event);
this.owner.basicInvalidatePart2(markerEntry, event, false /* Clear conflict occurred */, true);
this.owner.basicInvalidatePart3(markerEntry, event, true);
return true;
}
public void evictEntry(Object key) {
// noop
}
@Override
public void evictValue(Object key) {
// noop
}
/**
* Used by basicPut to signal the caller that the put was successful.
*/
@Immutable
private static final RegionEntry markerEntry = new ProxyRegionEntry();
@Override
public RegionEntry basicPut(EntryEventImpl event, long lastModified, boolean ifNew, boolean ifOld,
Object expectedOldValue, boolean requireOldValue, boolean overwriteDestroyed)
throws CacheWriterException, TimeoutException {
if (!event.isOriginRemote() && event.getOperation() != Operation.REPLACE) { // bug 42167 - don't
// convert replace
// to CREATE
event.makeCreate();
}
final CacheWriter cacheWriter = this.owner.basicGetWriter();
final boolean cacheWrite = !event.isOriginRemote() && !event.isNetSearch()
&& !event.getInhibitDistribution() && event.isGenerateCallbacks()
&& (cacheWriter != null || this.owner.hasServerProxy() || this.owner.scope.isDistributed());
if (cacheWrite) {
final Set netWriteRecipients;
if (cacheWriter == null && this.owner.scope.isDistributed()) {
CacheDistributionAdvisor cda = ((DistributedRegion) this.owner).getDistributionAdvisor();
netWriteRecipients = cda.adviseNetWrite();
} else {
netWriteRecipients = null;
}
if (event.getOperation() != Operation.REPLACE) { // bug #42167 - makeCreate() causes REPLACE
// to eventually become UPDATE
event.makeCreate();
}
this.owner.cacheWriteBeforePut(event, netWriteRecipients, cacheWriter, requireOldValue,
expectedOldValue);
}
owner.recordEvent(event);
lastModified = // fix for bug 40129
this.owner.basicPutPart2(event, markerEntry, true, lastModified,
false /* Clear conflict occurred */);
this.owner.basicPutPart3(event, markerEntry, true, lastModified, true, ifNew, ifOld,
expectedOldValue, requireOldValue);
return markerEntry;
}
@Override
public void writeSyncIfPresent(Object key, Runnable runner) {
// nothing needed
}
@Override
public void removeIfDestroyed(Object key) {
// nothing needed
}
@Override
public void txApplyDestroy(Object key, TransactionId rmtOrigin, TXRmtEvent event,
boolean inTokenMode, boolean inRI, Operation op, EventID eventId, Object aCallbackArgument,
List<EntryEventImpl> pendingCallbacks, FilterRoutingInfo filterRoutingInfo,
ClientProxyMembershipID bridgeContext, boolean isOperationRemote, TXEntryState txEntryState,
VersionTag versionTag, long tailKey) {
this.owner.txApplyDestroyPart2(markerEntry, key, inTokenMode,
false /* Clear conflict occurred */, false);
if (!inTokenMode) {
if (event != null) {
event.addDestroy(this.owner, markerEntry, key, aCallbackArgument);
}
if (shouldInvokeCallbacks(this.owner, !inTokenMode)) {
// fix for bug 39526
@Released
EntryEventImpl e =
txCallbackEventFactory.createCallbackEvent(this.owner, op, key, null,
rmtOrigin, event, eventId, aCallbackArgument, filterRoutingInfo, bridgeContext,
txEntryState, versionTag, tailKey);
switchEventOwnerAndOriginRemote(e, txEntryState == null);
pendingCallbacks.add(e);
}
}
}
@Override
public void txApplyInvalidate(Object key, Object newValue, boolean didDestroy,
TransactionId rmtOrigin, TXRmtEvent event, boolean localOp, EventID eventId,
Object aCallbackArgument, List<EntryEventImpl> pendingCallbacks,
FilterRoutingInfo filterRoutingInfo, ClientProxyMembershipID bridgeContext,
TXEntryState txEntryState, VersionTag versionTag, long tailKey) {
this.owner.txApplyInvalidatePart2(markerEntry, key, didDestroy, true);
if (this.owner.isInitialized()) {
if (event != null) {
event.addInvalidate(this.owner, markerEntry, key, newValue, aCallbackArgument);
}
if (shouldInvokeCallbacks(this.owner, this.owner.isInitialized())) {
// fix for bug 39526
@Released
EntryEventImpl e = txCallbackEventFactory.createCallbackEvent(this.owner,
localOp ? Operation.LOCAL_INVALIDATE : Operation.INVALIDATE, key, newValue, rmtOrigin,
event, eventId, aCallbackArgument, filterRoutingInfo, bridgeContext, txEntryState,
versionTag, tailKey);
switchEventOwnerAndOriginRemote(e, txEntryState == null);
pendingCallbacks.add(e);
}
}
}
@Override
public void txApplyPut(Operation putOp, Object key, Object newValue, boolean didDestroy,
TransactionId rmtOrigin, TXRmtEvent event, EventID eventId, Object aCallbackArgument,
List<EntryEventImpl> pendingCallbacks, FilterRoutingInfo filterRoutingInfo,
ClientProxyMembershipID bridgeContext, TXEntryState txEntryState, VersionTag versionTag,
long tailKey) {
Operation putOperation = putOp.getCorrespondingCreateOp();
long lastMod = owner.cacheTimeMillis();
this.owner.txApplyPutPart2(markerEntry, key, lastMod, true, didDestroy, false);
if (this.owner.isInitialized()) {
if (event != null) {
event.addPut(putOperation, this.owner, markerEntry, key, newValue, aCallbackArgument);
}
if (shouldInvokeCallbacks(this.owner, this.owner.isInitialized())) {
// fix for bug 39526
@Released
EntryEventImpl e = txCallbackEventFactory
.createCallbackEvent(this.owner, putOperation, key,
newValue, rmtOrigin, event, eventId, aCallbackArgument, filterRoutingInfo,
bridgeContext, txEntryState, versionTag, tailKey);
switchEventOwnerAndOriginRemote(e, txEntryState == null);
pendingCallbacks.add(e);
}
}
}
@Override
public void decTxRefCount(RegionEntry e) {
// nothing needed
}
@Override
public void removeEntry(Object key, RegionEntry value, boolean updateStats) {
// nothing to do
}
@Override
public void removeEntry(Object key, RegionEntry re, boolean updateStat, EntryEventImpl event,
InternalRegion owner) {
// nothing to do
}
/**
* Provides a dummy implementation of RegionEntry so that basicPut can return an instance that
* make the upper levels think it did the put.
*/
public static class ProxyRegionEntry implements RegionEntry {
@Override
public long getLastModified() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public long getLastAccessed() throws InternalStatisticsDisabledException {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public long getHitCount() throws InternalStatisticsDisabledException {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public long getMissCount() throws InternalStatisticsDisabledException {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public VersionStamp getVersionStamp() {
return null;
}
@Override
public boolean isTombstone() {
return false;
}
@Override
public VersionTag generateVersionTag(VersionSource member, boolean withDelta,
InternalRegion region, EntryEventImpl event) {
return null; // proxies don't do versioning
}
public void processVersionTag(EntryEvent ev) {
return;
}
@Override
public void makeTombstone(InternalRegion region, VersionTag version) {
return;
}
@Override
public void updateStatsForPut(long lastModifiedTime, long lastAccessedTime) {
// do nothing; called by LocalRegion.updateStatsForPut
}
@Override
public void setRecentlyUsed(RegionEntryContext context) {
// do nothing; called by LocalRegion.updateStatsForPut
}
@Override
public void updateStatsForGet(boolean hit, long time) {
// do nothing; no entry stats
}
@Override
public void txDidDestroy(long currentTime) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public void resetCounts() throws InternalStatisticsDisabledException {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public void removePhase1(InternalRegion region, boolean clear) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public void removePhase2() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean isRemoved() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean isRemovedPhase2() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean fillInValue(InternalRegion region, Entry entry, ByteArrayDataInput in,
DistributionManager distributionManager, final Version version) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean isOverflowedToDisk(InternalRegion region,
DistributedRegion.DiskPosition diskPosition) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public Object getKey() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public Object getValue(RegionEntryContext context) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public Object getValueRetain(RegionEntryContext context) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public void setValue(RegionEntryContext context, Object value) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public Object prepareValueForCache(RegionEntryContext context, Object value,
boolean isEntryUpdate) {
throw new IllegalStateException("Should never be called");
}
@Override
public Object getValue() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public Token getValueAsToken() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public Object getValueRetain(RegionEntryContext context, boolean decompress) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public Object getTransformedValue() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public Object getValueInVM(RegionEntryContext context) {
return null; // called by TXRmtEvent.createEvent
}
@Override
public Object getValueOnDisk(InternalRegion region) throws EntryNotFoundException {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public Object getValueOnDiskOrBuffer(InternalRegion region) throws EntryNotFoundException {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public Object getSerializedValueOnDisk(InternalRegion region) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean initialImagePut(InternalRegion region, long lastModified, Object newValue,
boolean wasRecovered, boolean acceptedVersionTag) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean initialImageInit(InternalRegion region, long lastModified, Object newValue,
boolean create, boolean wasRecovered, boolean acceptedVersionTag) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean destroy(InternalRegion region, EntryEventImpl event, boolean inTokenMode,
boolean cacheWrite, Object expectedOldValue, boolean forceDestroy,
boolean removeRecoveredEntry)
throws CacheWriterException, EntryNotFoundException, TimeoutException {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean getValueWasResultOfSearch() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public void setValueResultOfSearch(boolean value) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean dispatchListenerEvents(EntryEventImpl event) throws InterruptedException {
// note that we don't synchronize on the RE before dispatching events
event.invokeCallbacks(event.getRegion(), event.inhibitCacheListenerNotification(), false);
return true;
}
@Override
public boolean hasStats() {
return false;
}
@Override
public Object getValueInVMOrDiskWithoutFaultIn(InternalRegion region) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public Object getValueOffHeapOrDiskWithoutFaultIn(InternalRegion region) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean isUpdateInProgress() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public void setUpdateInProgress(boolean underUpdate) {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean isValueNull() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean isInvalid() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean isDestroyed() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public void setValueToNull() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean isInvalidOrRemoved() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean isDestroyedOrRemoved() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean isDestroyedOrRemovedButNotTombstone() {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public void returnToPool() {
// nothing
}
@Override
public void setValueWithTombstoneCheck(Object value, EntryEvent event)
throws RegionClearedException {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean isCacheListenerInvocationInProgress() {
return false;
}
@Override
public void setCacheListenerInvocationInProgress(boolean isListenerInvoked) {
// nothing
}
@Override
public void setValue(RegionEntryContext context, Object value, EntryEventImpl event)
throws RegionClearedException {
throw new UnsupportedOperationException(
String.format("No entry support on regions with DataPolicy %s",
DataPolicy.EMPTY));
}
@Override
public boolean isInUseByTransaction() {
return false;
}
@Override
public void incRefCount() {
// nothing
}
@Override
public void decRefCount(EvictionList lruList, InternalRegion region) {
// nothing
}
@Override
public void resetRefCount(EvictionList lruList) {
// nothing
}
@Override
public Object prepareValueForCache(RegionEntryContext context, Object value,
EntryEventImpl event, boolean isEntryUpdate) {
throw new IllegalStateException("Should never be called");
}
@Override
public boolean isEvicted() {
return false;
}
}
@Override
public void copyRecoveredEntries(RegionMap rm) {
throw new IllegalStateException("copyRecoveredEntries should never be called on proxy");
}
@Override
public boolean removeTombstone(RegionEntry re, VersionHolder destroyedVersion, boolean isEviction,
boolean isScheduledTombstone) {
throw new IllegalStateException("removeTombstone should never be called on a proxy");
}
@Override
public boolean isTombstoneNotNeeded(RegionEntry re, int destroyedVersion) {
throw new IllegalStateException("removeTombstone should never be called on a proxy");
}
@Override
public void setEntryFactory(RegionEntryFactory f) {
throw new IllegalStateException("Should not be called on a ProxyRegionMap");
}
@Override
public void updateEntryVersion(EntryEventImpl event) {
// Do nothing. Not applicable for clients.
}
@Override
public RegionEntry getEntryInVM(Object key) {
return null;
}
@Override
public RegionEntry getOperationalEntryInVM(Object key) {
return null;
}
@Override
public int sizeInVM() {
return 0;
}
@Override
public void close(BucketRegion bucketRegion) {
// nothing
}
@Override
public ARMLockTestHook getARMLockTestHook() {
return null;
}
@Override
public int getEntryOverhead() {
return 0;
}
@Override
public ConcurrentMapWithReusableEntries<Object, Object> getCustomEntryConcurrentHashMap() {
return null;
}
@Override
public void setEntryMap(ConcurrentMapWithReusableEntries<Object, Object> map) {}
}