All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.internal.cache.EntrySnapshot Maven / Gradle / Ivy

/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * Licensed 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. See accompanying
 * LICENSE file.
 */
package com.gemstone.gemfire.internal.cache;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Map;

import com.gemstone.gemfire.DataSerializable;
import com.gemstone.gemfire.cache.CacheStatistics;
import com.gemstone.gemfire.cache.EntryDestroyedException;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.StatisticsDisabledException;
import com.gemstone.gemfire.internal.cache.versions.VersionStamp;
import com.gemstone.gemfire.internal.cache.versions.VersionTag;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;

/**
   * A Region.Entry implementation for remote entries and all PR entries
   * 
   * @since 5.1
   * @author bruce
   */
  public final class EntrySnapshot implements Region.Entry, DataSerializable {

    private static final long serialVersionUID = -2139749921655693280L;

    /**
     * True if at the time this entry was created it represented a local data store.
     * False if it was fetched remotely.
     * This field is used by unit tests.
     */
    private boolean startedLocal;
    /** whether this entry has been destroyed */
    private boolean entryDestroyed;
    public transient LocalRegion region = null; 
    /**
     * the internal entry for this Entry's key
     */
    public transient NonLocalRegionEntry regionEntry; // would be final except for serialization needing default constructor

    /**
     * creates a new Entry that wraps the given RegionEntry object for the given
     * storage Region
     * @param allowTombstones TODO
     */
    public EntrySnapshot(RegionEntry regionEntry, LocalRegion dataRegion,LocalRegion region, boolean allowTombstones) {
      this.region = region;
      if (regionEntry instanceof NonLocalRegionEntry) {
        this.regionEntry = (NonLocalRegionEntry)regionEntry;
        this.startedLocal = false;
      } else {
        this.startedLocal = true;
        // note we always make these non-local now to handle PR buckets moving
        // out from under this Region.Entry.
        if (regionEntry.hasStats()) {
          this.regionEntry = NonLocalRegionEntryWithStats.newEntry(regionEntry,
              dataRegion, allowTombstones);
        }
        else {
          this.regionEntry = NonLocalRegionEntry.newEntry(regionEntry,
              dataRegion, allowTombstones);
        }
      }
    }

    /**
     * Used by unit tests. Only available on PR.
     * If, at the time this entry was created, it was initialized from a local data store
     * then this method returns true.
     * @since 6.0
     */
    public boolean wasInitiallyLocal() {
      return this.startedLocal;
    }

    public Object getKey() {
      checkEntryDestroyed();
      return regionEntry.getKeyCopy();
    }
    
    public VersionTag getVersionTag() {
      VersionStamp stamp = regionEntry.getVersionStamp();
      if (stamp != null) {
        return stamp.asVersionTag();
      }
      return null;
    }
    
    public Object getRawValue() {
      Object v = this.regionEntry.getValue(null);
      if (v == null) {
        return null;
      }
      if (v instanceof CachedDeserializable) {
        if (region.isCopyOnRead()) {
          v = ((CachedDeserializable)v).getDeserializedWritableCopy(null, null);
        }
        else {
          v = ((CachedDeserializable)v).getDeserializedValue(null, null);
        }
        if (v == Token.INVALID || v == Token.LOCAL_INVALID) {
          v = null;
        }
      }
      else {
        if (v == Token.INVALID || v == Token.LOCAL_INVALID) {
          v = null;
        }
        else {
          v = conditionalCopy(v);
        }
      }
      return v;
    }

    public Object getValue() {
      checkEntryDestroyed();
      return getRawValue();
    }

    /**
     * Makes a copy, if copy-on-get is enabled, of the specified object.
     * 
     * @since 4.0
     */
    private Object conditionalCopy(Object o) {
      return o;
    }

    public Object getUserAttribute() {
      checkEntryDestroyed();
      Map userAttr = region.entryUserAttributes;
      if (userAttr == null) {
        return null;
      }
      return userAttr.get(this.regionEntry.getKey());
    }

    public Object setUserAttribute(Object value) {
      checkEntryDestroyed();
      if (this.region.isTX()) {
        throw new UnsupportedOperationException(
            LocalizedStrings.TXEntry_UA_NOT_SUPPORTED.toLocalizedString());
      }
      if (region.entryUserAttributes == null) {
        region.entryUserAttributes = new Hashtable();
      }
      return region.entryUserAttributes.put(this.regionEntry
          .getKey(), value);
    }

    public boolean isDestroyed() {
      if (this.entryDestroyed) {
        return true;
      }
      if (region.isDestroyed()) {
        this.entryDestroyed = true;
      }
      else if (this.regionEntry.isRemoved()) {
        this.entryDestroyed = true;
      }
      // else the entry is somewhere else and we don't know if it's destroyed
      return this.entryDestroyed;
    }

    public Region getRegion() {
      checkEntryDestroyed();
      return region;
    }
    
    public CacheStatistics getStatistics() throws StatisticsDisabledException {
      checkEntryDestroyed();
      if (!regionEntry.hasStats()
          || !region.statisticsEnabled) {
          throw new StatisticsDisabledException(LocalizedStrings.PartitionedRegion_STATISTICS_DISABLED_FOR_REGION_0.toLocalizedString(region.getFullPath()));
      }
      return new CacheStatisticsImpl(this.regionEntry, region);
    }

    @Override
    public boolean equals(Object obj) {
      if (!(obj instanceof EntrySnapshot)) {
        return false;
      }
      EntrySnapshot ent = (EntrySnapshot)obj;
      return this.regionEntry.getKey().equals(ent.getKey());
    }

    @Override
    public int hashCode() {
      return this.regionEntry.getKey().hashCode();
    }

    public Object setValue(Object arg) {
      Object returnValue = region.put(this.getKey(), arg);
      this.regionEntry.setCachedValue(arg);
      return returnValue;
    }

    /*
     * (non-Javadoc)
     * @see com.gemstone.gemfire.cache.Region.Entry#isLocal()
     */
    public boolean isLocal() {
      // pr entries are always non-local to support the bucket being moved out
      // from under an entry
      return false;
    }

    @Override
    public String toString() {
      if (this.isDestroyed()) {
        return "EntrySnapshot(#destroyed#" + regionEntry.getKeyCopy()
            + "; version=" + this.getVersionTag() + ")";
      }
      else {
        return "EntrySnapshot(key=" + regionEntry.getKeyCopy() + ";valueInVM="
            + this.regionEntry.getValueInVM(null) + ')';
      }
    }

    /**
     * get the underlying RegionEntry object, which will not be fully functional
     * if isLocal() returns false
     * 
     * @return the underlying RegionEntry for this Entry
     */
    public RegionEntry getRegionEntry() {
      return this.regionEntry;
    }

    // ////////////////////////////////////
    // /////////////////////// P R I V A T E M E T H O D S
    // ////////////////////////////////////

    private void checkEntryDestroyed() throws EntryDestroyedException {
      if (isDestroyed()) {
        throw new EntryDestroyedException(LocalizedStrings.PartitionedRegion_ENTRY_DESTROYED.toLocalizedString());
      }
    }

    // for deserialization
    public EntrySnapshot() {
    }

    public EntrySnapshot(DataInput in,LocalRegion region) throws IOException, ClassNotFoundException {
      this.fromData(in);
      this.region = region;
    }
    
    public void setRegion(LocalRegion r) {
      this.region = r;
    }
    
    public void setRegionEntry(NonLocalRegionEntry re) {
      this.regionEntry = re;
    }

    // when externalized, we write the state of a non-local RegionEntry so it
    // can
    // be reconstituted anywhere
    public void toData(DataOutput out) throws IOException {
      out.writeBoolean(this.regionEntry instanceof NonLocalRegionEntryWithStats);
      this.regionEntry.toData(out);
    }

    public void fromData(DataInput in) throws IOException,
        ClassNotFoundException {
      this.startedLocal = false;
      boolean hasStats = in.readBoolean();
      if (hasStats) {
        this.regionEntry = NonLocalRegionEntryWithStats.newEntry();
      }
      else {
        this.regionEntry = NonLocalRegionEntry.newEntry();
      }
      this.regionEntry.fromData(in);
    }
  }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy