com.gemstone.gemfire.internal.cache.FilterRoutingInfo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gemfire-core Show documentation
Show all versions of gemfire-core Show documentation
SnappyData store based off Pivotal GemFireXD
The newest version!
/*
* 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 com.gemstone.gemfire.DataSerializable;
import com.gemstone.gemfire.DataSerializer;
import com.gemstone.gemfire.InternalGemFireError;
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.internal.HeapDataOutputStream;
import com.gemstone.gemfire.internal.InternalDataSerializer;
import com.gemstone.gemfire.internal.VersionedDataInputStream;
import com.gemstone.gemfire.internal.VersionedDataSerializable;
import com.gemstone.gemfire.internal.shared.Version;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* This class is used to hold the information about the servers and
* their Filters (CQs and Interest List) that are satisfied by the
* cache update operation.
* @since 6.5
* @author agingade
*/
public class FilterRoutingInfo implements VersionedDataSerializable {
private static boolean OLD_MEMBERS_OPTIMIZED = Boolean.getBoolean("optimized-cq-serialization");
private static Version[] serializationVersions = new Version[]{ Version.GFE_71 };
/** Set to true if any peer members has any filters. */
private boolean memberWithFilterInfoExists = false;
/** Holds filter local filter information. */
private transient FilterInfo localFilterInfo;
/** whether local interest has been computed (not CQs - just interest) */
private transient boolean hasLocalInterestBeenComputed;
/**
* Map containing peer-server to filter message.
*/
private HashMap serverFilterInfo =
new HashMap();
/**
* Sets the local CQ filter information.
* @param cqInfo map of server side CQ Name to CQ event type.
*/
public void setLocalCqInfo(HashMap cqInfo){
if (this.localFilterInfo == null) {
this.localFilterInfo = new FilterInfo();
}
this.localFilterInfo.cqs = cqInfo;
this.localFilterInfo.filterProcessedLocally = true;
}
/**
* Sets the local Interest information.
* @param clients interested clients with receiveValues=true.
* @param clientsInv interested clients with receiveValues=false;
*/
public void setLocalInterestedClients(Set clients, Set clientsInv){
if (this.localFilterInfo == null) {
this.localFilterInfo = new FilterInfo();
}
this.localFilterInfo.setInterestedClients(clients);
this.localFilterInfo.setInterestedClientsInv(clientsInv);
this.localFilterInfo.filterProcessedLocally = true;
this.hasLocalInterestBeenComputed = true;
}
/**
* returns true if local interest has been computed
*/
public boolean hasLocalInterestBeenComputed() {
return this.hasLocalInterestBeenComputed;
}
/**
* Returns local Filter information.
* @return FilterInfo local filter info having CQs and interested client info.
*/
public FilterInfo getLocalFilterInfo() {
return this.localFilterInfo;
}
/**
* Sets CQ routing information.
* @param member for which CQs are satisfied.
* @param cqInfo map of server side CQ Name to CQ event type.
*/
public void setCqRoutingInfo(InternalDistributedMember member, HashMap cqInfo) {
FilterInfo fInfo = new FilterInfo();
fInfo.setCQs(cqInfo);
this.serverFilterInfo.put(member, fInfo);
if (cqInfo.size() > 0) {
this.memberWithFilterInfoExists = true;
}
}
/**
* Sets interested clients routing information
* @param member on which the client interests are satisfied
* @param clients Set containing interested clients with receiveValues=true
* @param clientsInv Set containing interested clients with receiveValues=false
* @param longIDs whether the client IDs may be long integers
*/
public void addInterestedClients(InternalDistributedMember member,
Set clients, Set clientsInv, boolean longIDs) {
this.memberWithFilterInfoExists = true;
FilterInfo fInfo = this.serverFilterInfo.get(member);
if (fInfo == null){
fInfo = new FilterInfo();
this.serverFilterInfo.put(member, fInfo);
}
if (clients != null && clients.size() > 0) {
fInfo.setInterestedClients(clients);
}
if (clientsInv != null && clientsInv.size() > 0) {
fInfo.setInterestedClientsInv(clientsInv);
}
if (longIDs) {
fInfo.longIDs = longIDs;
}
}
/**
* Returns the members list that has filters satisfied.
* @return the members who have filter routing information
*/
public Set getMembers(){
return this.serverFilterInfo.keySet();
}
/**
* Returns true if the local filter information is set.
* @return whether there is local routing information in this object
*/
public boolean hasLocalFilterInfo() {
return this.localFilterInfo != null;
}
/**
* Returns true if there is any member with filters satisfied.
* @return true if we have any filter information in this object
*/
public boolean hasMemberWithFilterInfo() {
return this.memberWithFilterInfoExists;
}
/**
* Returns the Filter Information for the member.
* @param member the member whose filter information is desired
* @return the filter information for the given member
*/
public FilterInfo getFilterInfo(InternalDistributedMember member){
return this.serverFilterInfo.get(member);
}
/**
* This adds the filter information from the given routing object to this
* object's tables. This is used to merge routing information for putAll
* operations.
* @param eventRouting the routing information for a single putAll event
*/
public void addFilterInfo(FilterRoutingInfo eventRouting) {
for (Map.Entry entry:
eventRouting.serverFilterInfo.entrySet()) {
FilterInfo existing = this.serverFilterInfo.get(entry.getKey());
if (existing == null) {
existing = new FilterInfo();
this.serverFilterInfo.put(entry.getKey(), existing);
}
existing.addFilterInfo(entry.getValue());
}
if (eventRouting.localFilterInfo != null) {
if (this.localFilterInfo == null) {
this.localFilterInfo = new FilterInfo();
}
this.localFilterInfo.addFilterInfo(eventRouting.localFilterInfo);
}
this.memberWithFilterInfoExists |= eventRouting.memberWithFilterInfoExists;
}
/** DataSerializable methods */
public void fromData(DataInput in) throws IOException, ClassNotFoundException {
DistributedMember myID = null;
GemFireCacheImpl cache = GemFireCacheImpl.getInstance();
if (cache != null) {
myID = cache.getMyId();
}
int size = in.readInt();
for (int i=0; i < size; i++){
InternalDistributedMember member = InternalDistributedMember.readEssentialData(in);
FilterInfo fInfo = new FilterInfo();
InternalDataSerializer.invokeFromData(fInfo, in);
// we only need to retain the recipient's entry
if (myID == null || myID.equals(member)) {
this.serverFilterInfo.put(member, fInfo);
}
}
}
public void toData(DataOutput out) throws IOException {
int size = this.serverFilterInfo.size();
out.writeInt(size);
for (Map.Entry e: this.serverFilterInfo.entrySet()) {
InternalDistributedMember member = e.getKey();
member.writeEssentialData(out);
FilterInfo fInfo = e.getValue();
InternalDataSerializer.invokeToData(fInfo, out);
}
}
public Version[] getSerializationVersions() {
return serializationVersions;
}
@Override
public String toString() {
String result = "FilterRoutingInfo(";
if (this.localFilterInfo != null) {
result += "local=";
result += this.localFilterInfo;
if (this.serverFilterInfo != null) {
result += ", ";
}
}
if (this.serverFilterInfo != null) {
result +="remote=";
result += this.serverFilterInfo;
}
return result + ")";
}
/**
* This holds the information about the CQs and interest list.
*/
public static class FilterInfo implements VersionedDataSerializable {
public boolean longIDs;
public static final long serialVersionUID = 0;
/** Map holding Cq filterID and CqEvent Type */
private HashMap cqs;
/**
* serialized routing data. This is only deserialized when requested so that
* routing information for other members included in a cach op message
* stays serialized, reducing the cost of having to send all routing
* info to all members
*/
private transient byte[] myData;
/** version of creator of myData, needed for deserialization */
private transient Version myDataVersion;
/** Clients that are interested in the event and want values */
private Set interestedClients;
/** Clients that are interested in the event and want invalidations */
private Set interestedClientsInv;
/** To identify where the filter is processed, locally or in remote node */
public boolean filterProcessedLocally = false;
/** adds the content from another FilterInfo object. */
public void addFilterInfo(FilterInfo other){
if (other.cqs != null) {
if (this.cqs == null) {
this.cqs = new HashMap();
}
for (Map.Entry entry: other.cqs.entrySet()) {
this.cqs.put(entry.getKey(), entry.getValue());
}
}
if (other.interestedClients != null) {
if (this.interestedClients == null) {
this.interestedClients = new HashSet();
}
this.interestedClients.addAll(other.interestedClients);
}
if (other.interestedClientsInv != null) {
if (this.interestedClientsInv == null) {
this.interestedClientsInv = new HashSet();
}
this.interestedClientsInv.addAll(other.interestedClientsInv);
}
}
/** clears CQ routing information */
public void clearCQRouting() {
this.cqs = null;
}
private static Version[] serializationVersions = new Version[]{ Version.GFXD_14 };
public Version[] getSerializationVersions() {
return serializationVersions;
}
/** DataSerializable methods */
public void fromData(DataInput in) throws IOException, ClassNotFoundException {
this.myData = DataSerializer.readByteArray(in);
}
public void toData(DataOutput out) throws IOException {
HeapDataOutputStream hdos = new HeapDataOutputStream(1000, null);
if (this.cqs == null) {
hdos.writeBoolean(false);
} else {
hdos.writeBoolean(true);
InternalDataSerializer.writeArrayLength(cqs.size(), hdos);
for (Iterator it=this.cqs.entrySet().iterator(); it.hasNext(); ) {
Map.Entry e = (Map.Entry)it.next();
// most cq IDs and all event types are small ints, so we use an optimized
// write that serializes 7 bits at a time in a compact form
InternalDataSerializer.writeUnsignedVL(((Long)e.getKey()).longValue(), hdos);
InternalDataSerializer.writeUnsignedVL(((Integer)e.getValue()).intValue(), hdos);
}
}
InternalDataSerializer.writeSetOfLongs(this.interestedClients, this.longIDs, hdos);
InternalDataSerializer.writeSetOfLongs(this.interestedClientsInv, this.longIDs, hdos);
byte[] myData = hdos.toByteArray();
DataSerializer.writeByteArray(myData, out);
}
public void fromDataPre_GFXD_1_4_0_0(DataInput in) throws IOException, ClassNotFoundException {
if (OLD_MEMBERS_OPTIMIZED) {
this.myDataVersion = InternalDataSerializer.getVersionForDataStreamOrNull(in);
this.myData = DataSerializer.readByteArray(in);
} else {
this.cqs = DataSerializer.readHashMap(in);
this.interestedClients = InternalDataSerializer.readSetOfLongs(in);
this.interestedClientsInv = InternalDataSerializer.readSetOfLongs(in);
}
}
public void toDataPre_GFXD_1_4_0_0(DataOutput out) throws IOException {
if (OLD_MEMBERS_OPTIMIZED) {
HeapDataOutputStream hdos = new HeapDataOutputStream(1000,
InternalDataSerializer.getVersionForDataStream(out));
if (this.cqs == null) {
hdos.writeBoolean(false);
} else {
hdos.writeBoolean(true);
InternalDataSerializer.writeArrayLength(cqs.size(), hdos);
for (Iterator it=this.cqs.entrySet().iterator(); it.hasNext(); ) {
Map.Entry e = (Map.Entry)it.next();
// most cq IDs and all event types are small ints, so we use an optimized
// write that serializes 7 bits at a time in a compact form
InternalDataSerializer.writeUnsignedVL(((Long)e.getKey()).longValue(), hdos);
InternalDataSerializer.writeUnsignedVL(((Integer)e.getValue()).intValue(), hdos);
}
}
InternalDataSerializer.writeSetOfLongs(this.interestedClients, this.longIDs, hdos);
InternalDataSerializer.writeSetOfLongs(this.interestedClientsInv, this.longIDs, hdos);
byte[] myData = hdos.toByteArray();
DataSerializer.writeByteArray(myData, out);
} else {
DataSerializer.writeHashMap(this.cqs, out);
InternalDataSerializer.writeSetOfLongs(this.interestedClients, this.longIDs, out);
InternalDataSerializer.writeSetOfLongs(this.interestedClientsInv, this.longIDs, out);
}
}
public HashMap getCQs() {
if (this.cqs == null && this.myData != null) {
deserialize();
}
return this.cqs;
}
public void setCQs(HashMap cqs) {
this.cqs = cqs;
}
public Set getInterestedClients() {
if (this.interestedClients == null && this.myData != null) {
deserialize();
}
return this.interestedClients;
}
public void setInterestedClients(Set clients) {
this.interestedClients = clients;
}
public Set getInterestedClientsInv() {
if (this.interestedClientsInv == null && this.myData != null) {
deserialize();
}
return this.interestedClientsInv;
}
public void setInterestedClientsInv(Set clients) {
this.interestedClientsInv = clients;
}
/**
* FilterInfo fields are only deserialized if they are needed. We send
* all FilterInfo routings to all members that receive a cach op message
* but each member is only interested in its own routing, so there is no
* need to deserialize the routings for other members
*/
private void deserialize() {
try {
InputStream is = new ByteArrayInputStream(myData);
DataInputStream dis;
if (this.myDataVersion != null) {
dis = new VersionedDataInputStream(is, this.myDataVersion);
} else {
dis = new DataInputStream(is);
}
boolean hasCQs = dis.readBoolean();
if (hasCQs) {
int numEntries = InternalDataSerializer.readArrayLength(dis);
this.cqs = new HashMap(numEntries);
for (int i=0; i 0) {
sb.append("interestedClients:");
sb.append(this.interestedClients);
}
if (this.interestedClientsInv != null && this.interestedClientsInv.size() > 0) {
sb.append(", interestedClientsInv:");
sb.append(this.interestedClientsInv);
}
if (InternalDistributedSystem.getLoggerI18n().finerEnabled()) {
if (this.cqs != null) {
sb.append(", cqs=");
sb.append(this.cqs.keySet());
}
} else {
if (this.cqs != null) {
sb.append(", ").append(this.cqs.size()).append(" cqs");
}
}
return sb.toString();
}
}
}