| /* |
| * 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.io.DataInput; |
| import java.io.DataOutput; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.apache.geode.DataSerializer; |
| import org.apache.geode.cache.EvictionAttributes; |
| import org.apache.geode.cache.ExpirationAttributes; |
| import org.apache.geode.cache.PartitionAttributes; |
| import org.apache.geode.cache.Scope; |
| import org.apache.geode.cache.partition.PartitionListener; |
| import org.apache.geode.distributed.internal.membership.InternalDistributedMember; |
| import org.apache.geode.internal.ExternalizableDSFID; |
| import org.apache.geode.internal.InternalDataSerializer; |
| import org.apache.geode.internal.serialization.DeserializationContext; |
| import org.apache.geode.internal.serialization.KnownVersion; |
| import org.apache.geode.internal.serialization.SerializationContext; |
| import org.apache.geode.internal.util.Versionable; |
| import org.apache.geode.internal.util.VersionedArrayList; |
| |
| /** |
| * Maintains configuration information for a PartitionedRegion. Instances are stored in the |
| * allPartitionedRegion. |
| */ |
| public class PartitionRegionConfig extends ExternalizableDSFID implements Versionable { |
| |
| private int prId; |
| |
| private PartitionAttributesImpl pAttrs; |
| |
| private Scope scope = null; |
| |
| /** Nodes participating in this PartitionedRegion */ |
| private VersionedArrayList nodes = null; |
| |
| /** |
| * Flag to indicate whether the PartitionedRegion's destruction responsibility is taken up by |
| * someone |
| */ |
| private boolean isDestroying = false; |
| |
| /** |
| * Flag to indicate whether this region has been created on all of the members that host the |
| * region that this region is colocated with. Once a region is in this state, new members will |
| * have to create this region before they can host any data for the colocated regions |
| */ |
| private boolean isColocationComplete; |
| |
| private volatile boolean firstDataStoreCreated = false; |
| |
| /** |
| * The full path of the region. Used for resolving colocation chains. |
| */ |
| private String fullPath = null; |
| |
| private String partitionResolver = null; |
| |
| private String colocatedWith = null; |
| |
| private EvictionAttributes ea = new EvictionAttributesImpl(); |
| |
| private ExpirationAttributes regionTimeToLive = null; |
| |
| private ExpirationAttributes regionIdleTimeout = null; |
| |
| private ExpirationAttributes entryTimeToLive = null; |
| |
| private ExpirationAttributes entryIdleTimeout = null; |
| |
| private Set<FixedPartitionAttributesImpl> elderFPAs = null; |
| |
| private ArrayList<String> partitionListenerClassNames = new ArrayList<>(); |
| |
| public void setGatewaySenderIds(Set<String> gatewaySenderIds) { |
| this.gatewaySenderIds = Collections.unmodifiableSet(gatewaySenderIds); |
| } |
| |
| private Set<String> gatewaySenderIds = Collections.emptySet(); |
| |
| /** |
| * Default constructor for DataSerializer |
| */ |
| public PartitionRegionConfig() { |
| // nothing |
| } |
| |
| PartitionRegionConfig(int prId, String path, PartitionAttributes prAtt, Scope sc, |
| EvictionAttributes ea, final ExpirationAttributes regionIdleTimeout, |
| final ExpirationAttributes regionTimeToLive, final ExpirationAttributes entryIdleTimeout, |
| final ExpirationAttributes entryTimeToLive, Set<String> gatewaySenderIds) { |
| this.prId = prId; |
| pAttrs = (PartitionAttributesImpl) prAtt; |
| scope = sc; |
| isDestroying = false; |
| nodes = new VersionedArrayList(); |
| if (prAtt.getPartitionResolver() != null) { |
| partitionResolver = prAtt.getPartitionResolver().getClass().getName(); |
| } |
| colocatedWith = prAtt.getColocatedWith(); |
| if (prAtt.getLocalMaxMemory() > 0) { |
| this.ea = ea; |
| firstDataStoreCreated = prAtt.getLocalMaxMemory() > 0; |
| } |
| this.regionIdleTimeout = regionIdleTimeout; |
| this.regionTimeToLive = regionTimeToLive; |
| this.entryIdleTimeout = entryIdleTimeout; |
| this.entryTimeToLive = entryTimeToLive; |
| isColocationComplete = colocatedWith == null; |
| fullPath = path; |
| elderFPAs = new LinkedHashSet<>(); |
| PartitionListener[] prListeners = prAtt.getPartitionListeners(); |
| if (prListeners != null && prListeners.length != 0) { |
| for (PartitionListener listener : prListeners) { |
| partitionListenerClassNames.add(listener.getClass().getName()); |
| } |
| } |
| this.gatewaySenderIds = gatewaySenderIds; |
| } |
| |
| public Set<String> getGatewaySenderIds() { |
| return gatewaySenderIds; |
| } |
| |
| /** |
| * Returns a the list of nodes that participate in the PartitionedRegion |
| * |
| * @return a copy of the list of nodes that the caller is free to modify |
| */ |
| Set<Node> getNodes() { |
| if (nodes != null) { |
| return nodes.getListCopy(); |
| } |
| return null; |
| } |
| |
| /** |
| * Return a safe, light weight size of the nodes |
| * |
| * @return number of VMs that participate in the PartitionedRegion |
| */ |
| int getNumberOfNodes() { |
| if (nodes != null) { |
| return nodes.size(); |
| } else { |
| return 0; |
| } |
| } |
| |
| /** |
| * Safely checks to see if the provided Node participates in the PartitionedRegion return true if |
| * the Node participates in the PartitionedRegion |
| */ |
| boolean containsNode(Node check) { |
| if (nodes != null) { |
| return nodes.contains(check); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Safely checks to see if the provided Node participates in the PartitionedRegion return true if |
| * the Node participates in the PartitionedRegion |
| */ |
| boolean containsMember(InternalDistributedMember memberId) { |
| if (nodes != null) { |
| for (Node node : nodes) { |
| if (memberId.equals(node.getMemberId())) { |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Adds a new node to this configuration |
| */ |
| void addNode(Node newNode) { |
| if (nodes != null) { |
| nodes.add(newNode); |
| } |
| } |
| |
| /** |
| * Removes a node from this configuration |
| */ |
| void removeNode(Node targetNode) { |
| if (nodes != null) { |
| nodes.remove(targetNode); |
| } |
| } |
| |
| public int getPRId() { |
| return prId; |
| } |
| |
| PartitionAttributes getPartitionAttrs() { |
| return pAttrs; |
| } |
| |
| Scope getScope() { |
| return scope; |
| } |
| |
| @Override |
| public String toString() { |
| String ret = "PartitionRegionConfig@" + System.identityHashCode(this) + ";prId=" + prId |
| + ";scope=" + scope + ";partition attributes=" + pAttrs + ";partitionResolver=" |
| + partitionResolver + ";colocatedWith=" + colocatedWith + ";eviction attributes=" |
| + ea + ";regionIdleTimeout= " + regionIdleTimeout + ";regionTimeToLive= " |
| + regionTimeToLive + ";entryIdleTimeout= " + entryIdleTimeout |
| + ";entryTimeToLive= " + entryTimeToLive + "'elderFPAs=" + elderFPAs |
| + "'gatewaySenderIds=" + gatewaySenderIds + ";nodes="; |
| if (nodes != null) { |
| return ret + nodes; |
| } else { |
| return ret + "null"; |
| } |
| } |
| |
| @Override |
| public int getDSFID() { |
| return PARTITION_REGION_CONFIG; |
| } |
| |
| @Override |
| public void toData(DataOutput out, |
| SerializationContext context) throws IOException { |
| out.writeInt(prId); |
| out.writeByte(scope.ordinal); |
| InternalDataSerializer.invokeToData(pAttrs, out); |
| out.writeBoolean(isDestroying); |
| out.writeBoolean(isColocationComplete); |
| InternalDataSerializer.invokeToData(nodes, out); |
| DataSerializer.writeString(partitionResolver, out); |
| DataSerializer.writeString(colocatedWith, out); |
| DataSerializer.writeString(fullPath, out); |
| InternalDataSerializer.invokeToData(ea, out); |
| InternalDataSerializer.invokeToData(regionIdleTimeout, out); |
| InternalDataSerializer.invokeToData(regionTimeToLive, out); |
| InternalDataSerializer.invokeToData(entryIdleTimeout, out); |
| InternalDataSerializer.invokeToData(entryTimeToLive, out); |
| out.writeBoolean(firstDataStoreCreated); |
| DataSerializer.writeObject(elderFPAs, out); |
| DataSerializer.writeArrayList(partitionListenerClassNames, out); |
| if (gatewaySenderIds.isEmpty()) { |
| DataSerializer.writeObject(null, out); |
| } else { |
| DataSerializer.writeObject(gatewaySenderIds, out); |
| } |
| } |
| |
| @Override |
| public void fromData(DataInput in, |
| DeserializationContext context) throws IOException, ClassNotFoundException { |
| prId = in.readInt(); |
| scope = Scope.fromOrdinal(in.readByte()); |
| pAttrs = PartitionAttributesImpl.createFromData(in); |
| isDestroying = in.readBoolean(); |
| isColocationComplete = in.readBoolean(); |
| nodes = new VersionedArrayList(); |
| InternalDataSerializer.invokeFromData(nodes, in); |
| partitionResolver = DataSerializer.readString(in); |
| colocatedWith = DataSerializer.readString(in); |
| fullPath = DataSerializer.readString(in); |
| ea = EvictionAttributesImpl.createFromData(in); |
| regionIdleTimeout = ExpirationAttributes.createFromData(in); |
| regionTimeToLive = ExpirationAttributes.createFromData(in); |
| entryIdleTimeout = ExpirationAttributes.createFromData(in); |
| entryTimeToLive = ExpirationAttributes.createFromData(in); |
| firstDataStoreCreated = in.readBoolean(); |
| elderFPAs = DataSerializer.readObject(in); |
| if (elderFPAs == null) { |
| elderFPAs = new LinkedHashSet<>(); |
| } |
| partitionListenerClassNames = DataSerializer.readArrayList(in); |
| gatewaySenderIds = DataSerializer.readObject(in); |
| if (gatewaySenderIds == null) { |
| gatewaySenderIds = Collections.emptySet(); |
| } |
| } |
| |
| /** |
| * This method returns true is a node has taken a responsibility of destroying the |
| * PartitionedRegion globally |
| * |
| * @return true, if a node has taken a responsibility of destroying the PartitionedRegion globally |
| * else it returns false |
| */ |
| boolean getIsDestroying() { |
| return isDestroying; |
| } |
| |
| /** |
| * This method sets the isDestroying flag to true, to indicate that the PartitionedRegion's |
| * destruction responsibility is taken up by a node. |
| * |
| */ |
| void setIsDestroying() { |
| isDestroying = true; |
| } |
| |
| void setColocationComplete(PartitionedRegion partitionedRegion) { |
| isColocationComplete = true; |
| partitionedRegion.executeColocationCallbacks(); |
| } |
| |
| public void setEntryIdleTimeout(ExpirationAttributes idleTimeout) { |
| entryIdleTimeout = idleTimeout; |
| } |
| |
| public void setEntryTimeToLive(ExpirationAttributes timeToLive) { |
| entryTimeToLive = timeToLive; |
| } |
| |
| public boolean isGreaterNodeListVersion(final PartitionRegionConfig other) { |
| return nodes.isNewerThan(other.nodes); |
| } |
| |
| @Override |
| public Comparable getVersion() { |
| return nodes.getVersion(); |
| } |
| |
| @Override |
| public boolean isNewerThan(Versionable other) { |
| return nodes.isNewerThan(other); |
| } |
| |
| @Override |
| public boolean isSame(Versionable other) { |
| return nodes.isSame(other); |
| } |
| |
| @Override |
| public boolean isOlderThan(Versionable other) { |
| return nodes.isOlderThan(other); |
| } |
| |
| public String getResolverClassName() { |
| return partitionResolver; |
| } |
| |
| public String getColocatedWith() { |
| return colocatedWith; |
| } |
| |
| public String getFullPath() { |
| return fullPath; |
| } |
| |
| public boolean isColocationComplete() { |
| return isColocationComplete; |
| } |
| |
| public EvictionAttributes getEvictionAttributes() { |
| return ea; |
| } |
| |
| public ExpirationAttributes getEntryIdleTimeout() { |
| return entryIdleTimeout; |
| } |
| |
| public ExpirationAttributes getEntryTimeToLive() { |
| return entryTimeToLive; |
| } |
| |
| public ExpirationAttributes getRegionIdleTimeout() { |
| return regionIdleTimeout; |
| } |
| |
| public ExpirationAttributes getRegionTimeToLive() { |
| return regionTimeToLive; |
| } |
| |
| public boolean isFirstDataStoreCreated() { |
| return firstDataStoreCreated; |
| } |
| |
| public void addFPAs(List<FixedPartitionAttributesImpl> fpaList) { |
| if (elderFPAs != null) { |
| elderFPAs.addAll(fpaList); |
| } |
| } |
| |
| public Set<FixedPartitionAttributesImpl> getElderFPAs() { |
| return elderFPAs; |
| } |
| |
| public ArrayList<String> getPartitionListenerClassNames() { |
| return partitionListenerClassNames; |
| } |
| |
| public boolean hasSameDataStoreMembers(PartitionRegionConfig prConfig) { |
| for (Node node : getNodes()) { |
| if (!prConfig.containsMember(node.getMemberId()) |
| && ((node.getPRType() == Node.ACCESSOR_DATASTORE) |
| || (node.getPRType() == Node.FIXED_PR_DATASTORE))) { |
| return false; |
| } |
| } |
| for (Node node : prConfig.getNodes()) { |
| if (!containsMember(node.getMemberId()) && ((node.getPRType() == Node.ACCESSOR_DATASTORE) |
| || (node.getPRType() == Node.FIXED_PR_DATASTORE))) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public KnownVersion[] getSerializationVersions() { |
| return null; |
| } |
| |
| public void setDatastoreCreated(EvictionAttributes evictionAttributes) { |
| firstDataStoreCreated = true; |
| ea = evictionAttributes; |
| } |
| } |