com.gemstone.gemfire.internal.cache.tier.sockets.VersionedObjectList Maven / Gradle / Ivy
Show all versions of gemfire-core Show documentation
/*
* 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.tier.sockets;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.InternalGemFireException;
import com.gemstone.gemfire.distributed.DistributedMember;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
import com.gemstone.gemfire.distributed.internal.membership.InternalDistributedMember;
import com.gemstone.gemfire.i18n.LogWriterI18n;
import com.gemstone.gemfire.internal.DataSerializableFixedID;
import com.gemstone.gemfire.internal.InternalDataSerializer;
import com.gemstone.gemfire.internal.cache.KeyWithRegionContext;
import com.gemstone.gemfire.internal.cache.LocalRegion;
import com.gemstone.gemfire.internal.cache.versions.DiskVersionTag;
import com.gemstone.gemfire.internal.cache.versions.VersionSource;
import com.gemstone.gemfire.internal.cache.versions.VersionTag;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.internal.shared.Version;
/**
* A refinement of ObjectPartList that adds per-entry versionTags and
* has its own serialized form to allow key lists when there are no object components.
*
* This class also implements Externalizable so that it can be serialized as
* part of a PutAllPartialResultException.
*
* @author Bruce Schuchardt
* @since 7.0
*/
public class VersionedObjectList extends ObjectPartList implements Externalizable {
public static final boolean DEBUG = Boolean.getBoolean("gemfire.VersionedObjectList.DEBUG");
ArrayList versionTags;
private boolean regionIsVersioned;
/** a flag telling us that after transmission of the list all objects should remain serialized */
private boolean serializeValues;
/**
* add a new entry to the list
* @param key the entry's key
* @param versionTag the version tag for the entry, or null if there is no version information available
*/
public void addKeyAndVersion(Object key, VersionTag versionTag) {
if (DEBUG) {
InternalDistributedSystem.getLoggerI18n().info(LocalizedStrings.DEBUG,
"VersionedObjectList.addKeyAndVersion("+key+"; "+versionTag+")");
}
if (this.objects.size() > 0) {
throw new IllegalStateException("attempt to add key/version to a list containing objects");
}
this.keys.add(key);
if (this.regionIsVersioned) {
// Assert.assertTrue(versionTag != null);
this.versionTags.add(versionTag);
}
}
@Override
public void addPart(Object key, Object value, byte objectType, VersionTag versionTag) {
if (DEBUG) {
InternalDistributedSystem.getLoggerI18n().info(LocalizedStrings.DEBUG,
"addPart("+key+"; "+value+"; "+objectType+"; "+versionTag /*+ "\n list=" + this*/);
}
super.addPart(key, value, objectType, versionTag);
if (this.regionIsVersioned) {
int tagsSize = this.versionTags.size();
if (keys != null && (tagsSize != this.keys.size()-1)) {
// this should not happen - either all or none of the entries should have tags
throw new InternalGemFireException();
}
if (this.objects != null && (this.objects.size() > 0) && (tagsSize != this.objects.size()-1)) {
// this should not happen - either all or none of the entries should have tags
throw new InternalGemFireException();
}
// Assert.assertTrue(versionTag != null);
this.versionTags.add(versionTag);
}
}
/**
* add a versioned "map" entry to the list
*
* @param key
* @param value
* @param versionTag
*/
public void addObject(Object key, Object value, VersionTag versionTag) {
addPart(key, value, OBJECT, versionTag);
}
// public methods
public VersionedObjectList() {
super();
this.versionTags = new ArrayList();
}
public VersionedObjectList(boolean serializeValues) {
this();
this.serializeValues = serializeValues;
}
public VersionedObjectList(int maxSize, boolean hasKeys, boolean regionIsVersioned) {
this(maxSize, hasKeys, regionIsVersioned, false);
}
public VersionedObjectList(int maxSize, boolean hasKeys, boolean regionIsVersioned, boolean serializeValues) {
super(maxSize, hasKeys);
if (regionIsVersioned) {
this.versionTags = new ArrayList(maxSize);
this.regionIsVersioned = true;
} else {
this.versionTags = new ArrayList();
}
this.serializeValues = serializeValues;
}
/**
* replace null membership IDs in version tags with the given member ID.
* VersionTags received from a server may have null IDs because they were
* operations performed by that server. We transmit them as nulls to cut
* costs, but have to do the swap on the receiving end (in the client)
* @param sender
*/
public void replaceNullIDs(DistributedMember sender) {
for (VersionTag versionTag: versionTags) {
if (versionTag != null) {
versionTag.replaceNullIDs((InternalDistributedMember) sender);
}
}
}
@Override
public void addObjectPartForAbsentKey(Object key, Object value) {
addPart(key, value, KEY_NOT_AT_SERVER, null);
}
/**
* Add a part for a destroyed or missing entry. If the version tag is
* not null this represents a tombstone.
* @param key
* @param value
* @param version
*/
public void addObjectPartForAbsentKey(Object key, Object value, VersionTag version) {
addPart(key, value, KEY_NOT_AT_SERVER, version);
}
@Override
public void addAll(ObjectPartList other) {
if (DEBUG) {
InternalDistributedSystem.getLoggerI18n().info(LocalizedStrings.DEBUG, "VOL.addAll(other="+other+"; this="+this/*, new Exception("stack trace")*/);
}
int myTypeArrayLength = this.hasKeys? this.keys.size() : this.objects.size();
int otherTypeArrayLength = other.hasKeys? other.keys.size() : other.objects.size();
super.addAll(other);
VersionedObjectList vother = (VersionedObjectList)other;
this.regionIsVersioned |= vother.regionIsVersioned;
this.versionTags.addAll(vother.versionTags);
if (myTypeArrayLength > 0 || otherTypeArrayLength > 0) {
// LogWriterI18n log = InternalDistributedSystem.getLoggerI18n();
// log.fine("this="+this+"\nother=" + other);
int newSize = myTypeArrayLength + otherTypeArrayLength;
if (this.objectTypeArray != null) {
newSize = Math.max(newSize,this.objectTypeArray.length);
if (this.objectTypeArray.length < newSize) { // need more room
byte[] temp = this.objectTypeArray;
this.objectTypeArray = new byte[newSize];
System.arraycopy(temp, 0, this.objectTypeArray, 0, temp.length);
}
} else {
this.objectTypeArray = new byte[newSize];
}
if (other.objectTypeArray != null) {
System.arraycopy(other.objectTypeArray, 0, this.objectTypeArray, myTypeArrayLength, otherTypeArrayLength);
}
}
}
public List getVersionTags() {
return Collections.unmodifiableList(this.versionTags);
}
public boolean hasVersions() {
return this.versionTags.size() > 0;
}
/** clear the version tags from this list */
public void clearVersions() {
this.versionTags = new ArrayList(Math.max(50, this.size()));
}
/**
* Add a version, assuming that the key list has already been established and we are now
* filling in version information.
* @param tag the version tag to add
*/
public void addVersion(VersionTag tag) {
this.versionTags.add(tag);
}
/**
* save the current key/tag pairs in the given map
* @param vault
*/
public void saveVersions(Map