GEODE-3232: Get a snapshot of maps when serializing FilterProfile

Avoiding a race when serializing a CopyOnWrite data structures be
grabbing a copy first.

This closes #640


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/aa4878ef
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/aa4878ef
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/aa4878ef

Branch: refs/heads/feature/GEM-1483
Commit: aa4878ef19d27a78454dc10b451199f088a2f37d
Parents: 78900eb
Author: Dan Smith <upthewatersp...@apache.org>
Authored: Tue Jul 18 15:49:21 2017 -0700
Committer: Dan Smith <upthewatersp...@apache.org>
Committed: Tue Jul 18 15:49:21 2017 -0700

----------------------------------------------------------------------
 .../geode/internal/cache/FilterProfile.java     | 49 +++++++++++---------
 .../util/concurrent/CopyOnWriteHashMap.java     |  4 ++
 .../sanctionedDataSerializables.txt             |  4 +-
 3 files changed, 32 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/aa4878ef/geode-core/src/main/java/org/apache/geode/internal/cache/FilterProfile.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/cache/FilterProfile.java 
b/geode-core/src/main/java/org/apache/geode/internal/cache/FilterProfile.java
index 9a4eca3..f94a1ee 100755
--- 
a/geode-core/src/main/java/org/apache/geode/internal/cache/FilterProfile.java
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/cache/FilterProfile.java
@@ -126,36 +126,37 @@ public class FilterProfile implements 
DataSerializableFixedID {
    * The keys in which clients are interested. This is a map keyed on client 
id, with a HashSet of
    * the interested keys as the values.
    */
-  private final Map<Object, Set> keysOfInterest = new CopyOnWriteHashMap<>();
+  private final CopyOnWriteHashMap<Object, Set> keysOfInterest = new 
CopyOnWriteHashMap<>();
 
-  private final Map<Object, Set> keysOfInterestInv = new 
CopyOnWriteHashMap<>();
+  private final CopyOnWriteHashMap<Object, Set> keysOfInterestInv = new 
CopyOnWriteHashMap<>();
 
   /**
    * The patterns in which clients are interested. This is a map keyed on 
client id, with a HashMap
    * (key name to compiled pattern) as the values.
    */
-  private final Map<Object, Map<Object, Pattern>> patternsOfInterest = new 
CopyOnWriteHashMap<>();
+  private final CopyOnWriteHashMap<Object, Map<Object, Pattern>> 
patternsOfInterest =
+      new CopyOnWriteHashMap<>();
 
-  private final Map<Object, Map<Object, Pattern>> patternsOfInterestInv =
+  private final CopyOnWriteHashMap<Object, Map<Object, Pattern>> 
patternsOfInterestInv =
       new CopyOnWriteHashMap<>();
 
   /**
    * The filtering classes in which clients are interested. This is a map 
keyed on client id, with a
    * HashMap (key name to {@link InterestFilter}) as the values.
    */
-  private final Map<Object, Map> filtersOfInterest = new 
CopyOnWriteHashMap<>();
+  private final CopyOnWriteHashMap<Object, Map> filtersOfInterest = new 
CopyOnWriteHashMap<>();
 
-  private final Map<Object, Map> filtersOfInterestInv = new 
CopyOnWriteHashMap<>();
+  private final CopyOnWriteHashMap<Object, Map> filtersOfInterestInv = new 
CopyOnWriteHashMap<>();
 
   /**
    * Set of clients that we have ALL_KEYS interest for and who want updates
    */
-  private final Set<Long> allKeyClients = new CopyOnWriteHashSet<>();
+  private final CopyOnWriteHashSet<Long> allKeyClients = new 
CopyOnWriteHashSet<>();
 
   /**
    * Set of clients that we have ALL_KEYS interest for and who want 
invalidations
    */
-  private final Set<Long> allKeyClientsInv = new CopyOnWriteHashSet<>();
+  private final CopyOnWriteHashSet<Long> allKeyClientsInv = new 
CopyOnWriteHashSet<>();
 
   /**
    * The region associated with this profile
@@ -171,7 +172,7 @@ public class FilterProfile implements 
DataSerializableFixedID {
   AtomicInteger cqCount;
 
   /** CQs that are registered on the remote node **/
-  private final Map cqs = new CopyOnWriteHashMap();
+  private final CopyOnWriteHashMap<String, ServerCQ> cqs = new 
CopyOnWriteHashMap<>();
 
   /* the ID of the member that this profile describes */
   private DistributedMember memberID;
@@ -1500,24 +1501,26 @@ public class FilterProfile implements 
DataSerializableFixedID {
 
   public void toData(DataOutput out) throws IOException {
     InternalDataSerializer.invokeToData(((InternalDistributedMember) 
memberID), out);
-    InternalDataSerializer.writeSetOfLongs(this.allKeyClients, 
this.clientMap.hasLongID, out);
-    DataSerializer.writeHashMap(this.keysOfInterest, out);
-    DataSerializer.writeHashMap(this.patternsOfInterest, out);
-    DataSerializer.writeHashMap(this.filtersOfInterest, out);
-
-    InternalDataSerializer.writeSetOfLongs(this.allKeyClientsInv, 
this.clientMap.hasLongID, out);
-    DataSerializer.writeHashMap(this.keysOfInterestInv, out);
-    DataSerializer.writeHashMap(this.patternsOfInterestInv, out);
-    DataSerializer.writeHashMap(this.filtersOfInterestInv, out);
+    InternalDataSerializer.writeSetOfLongs(this.allKeyClients.getSnapshot(),
+        this.clientMap.hasLongID, out);
+    DataSerializer.writeHashMap(this.keysOfInterest.getSnapshot(), out);
+    DataSerializer.writeHashMap(this.patternsOfInterest.getSnapshot(), out);
+    DataSerializer.writeHashMap(this.filtersOfInterest.getSnapshot(), out);
+
+    InternalDataSerializer.writeSetOfLongs(this.allKeyClientsInv.getSnapshot(),
+        this.clientMap.hasLongID, out);
+    DataSerializer.writeHashMap(this.keysOfInterestInv.getSnapshot(), out);
+    DataSerializer.writeHashMap(this.patternsOfInterestInv.getSnapshot(), out);
+    DataSerializer.writeHashMap(this.filtersOfInterestInv.getSnapshot(), out);
 
     // Write CQ info.
-    Map theCQs = this.cqs;
+    Map<String, ServerCQ> theCQs = this.cqs.getSnapshot();
     int size = theCQs.size();
     InternalDataSerializer.writeArrayLength(size, out);
-    for (Iterator it = theCQs.entrySet().iterator(); it.hasNext();) {
-      Map.Entry entry = (Map.Entry) it.next();
-      String name = (String) entry.getKey();
-      ServerCQ cq = (ServerCQ) entry.getValue();
+    for (Iterator<Map.Entry<String, ServerCQ>> it = 
theCQs.entrySet().iterator(); it.hasNext();) {
+      Map.Entry<String, ServerCQ> entry = it.next();
+      String name = entry.getKey();
+      ServerCQ cq = entry.getValue();
       DataSerializer.writeString(name, out);
       InternalDataSerializer.invokeToData(cq, out);
     }

http://git-wip-us.apache.org/repos/asf/geode/blob/aa4878ef/geode-core/src/main/java/org/apache/geode/internal/util/concurrent/CopyOnWriteHashMap.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/internal/util/concurrent/CopyOnWriteHashMap.java
 
b/geode-core/src/main/java/org/apache/geode/internal/util/concurrent/CopyOnWriteHashMap.java
index bb7d34d..9c90078 100644
--- 
a/geode-core/src/main/java/org/apache/geode/internal/util/concurrent/CopyOnWriteHashMap.java
+++ 
b/geode-core/src/main/java/org/apache/geode/internal/util/concurrent/CopyOnWriteHashMap.java
@@ -163,6 +163,10 @@ public class CopyOnWriteHashMap<K, V> extends 
AbstractMap<K, V>
     return clone;
   }
 
+  public Map<K, V> getSnapshot() {
+    return Collections.unmodifiableMap(map);
+  }
+
   @Override
   public synchronized V putIfAbsent(K key, V value) {
     V oldValue = map.get(key);

http://git-wip-us.apache.org/repos/asf/geode/blob/aa4878ef/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt
----------------------------------------------------------------------
diff --git 
a/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt
 
b/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt
index e2a708d..e9280f8 100644
--- 
a/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt
+++ 
b/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedDataSerializables.txt
@@ -1011,8 +1011,8 @@ 
fromData,33,2a2bb9001b0100b500072a2bb8001cc0001db500052a2bb8001cc0001eb50003b1
 toData,27,2b2ab40007b9001902002ab400052bb8001a2ab400032bb8001ab1
 
 org/apache/geode/internal/cache/FilterProfile,2
-fromData,210,bb013159b701324d2c2bb801332a2cb500202ab4000d2bb80134b900300200572ab400052bb80135b9007802002ab400072bb80135b9007802002ab400092bb80135b9007802002ab4000e2bb80134b900300200572ab400062bb80135b9007802002ab400082bb80135b9007802002ab4000a2bb80135b9007802002bb801363e1d9e004f05b80138360403360515051da2002c2bb801393a062bb8013a3a072a1906190703b6013b2ab4000f19061907b90054030057840501a7ffd41504b8013857a7000e3a081504b80138571908bfb1
-toData,181,2ab40020c001312bb8013d2ab4000d2ab40023b401182bb8013e2ab400052bb8013f2ab400072bb8013f2ab400092bb8013f2ab4000e2ab40023b401182bb8013e2ab400062bb8013f2ab400082bb8013f2ab4000a2bb8013f2ab4000f4d2cb900b901003e1d2bb801402cb900ae0100b900af01003a041904b900b001009900361904b900b10100c000b23a051905b9011b0100c0003c3a061905b900b30100c000843a0719062bb8014119072bb8013da7ffc6b1
+fromData,192,bb013659b701374d2c2bb801382a2cb500202ab4000d2bb80139b60070572ab400052bb8013ab6013b2ab400072bb8013ab6013b2ab400092bb8013ab6013b2ab4000e2bb80139b60070572ab400062bb8013ab6013b2ab400082bb8013ab6013b2ab4000a2bb8013ab6013b2bb8013c3e1d9e004d05b8013e360403360515051da2002a2bb8013f3a062bb801403a072a1906190703b601412ab4000f19061907b6008957840501a7ffd61504b8013e57a7000e3a081504b8013e571908bfb1
+toData,208,2ab40020c001362bb801432ab4000db6006e2ab40023b4011b2bb801442ab40005b601452bb801462ab40007b601452bb801462ab40009b601452bb801462ab4000eb6006e2ab40023b4011b2bb801442ab40006b601452bb801462ab40008b601452bb801462ab4000ab601452bb801462ab4000fb601454d2cb900bc01003e1d2bb801472cb9011d0100b900b201003a041904b900b301009900361904b900b40100c000b53a051905b9011f0100c0003c3a061905b900b60100c000853a0719062bb8014819072bb80143a7ffc6b1
 
 org/apache/geode/internal/cache/FilterProfile$OperationMessage,2
 
fromData,129,2a2bb700522a2bb900530100b500092a2bb900540100b500412ab800552bb90056010032b500232a2bb900570100b500292a2bb900580100b5004a2ab40023b8004c99002c2a2bb900540100b500322ab40023b2004ea5000d2ab40023b2004fa600202a2bb80059b50033a700152a2bb900580100b500252a2bb8005ab50027b1

Reply via email to