You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sn...@apache.org on 2015/05/15 00:17:27 UTC

cassandra git commit: Make Functions.declared thread-safe

Repository: cassandra
Updated Branches:
  refs/heads/trunk 4a5c282f7 -> 7f9ed0ddb


Make Functions.declared thread-safe

Patch by Robert Stupp; Reviewed by Tyler Hobbs for CASSANDRA-9366


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

Branch: refs/heads/trunk
Commit: 7f9ed0ddbaabbcc94311e25b2df60415da15ede7
Parents: 4a5c282
Author: Robert Stupp <sn...@snazy.de>
Authored: Fri May 15 00:16:18 2015 +0200
Committer: Robert Stupp <sn...@snazy.de>
Committed: Fri May 15 00:16:18 2015 +0200

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 .../cassandra/cql3/functions/Functions.java     | 70 ++++++++++++++------
 2 files changed, 52 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/7f9ed0dd/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 325a5f3..0efba98 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 2.2
+ * Make Functions.declared thread-safe
  * Add client warnings to native protocol v4 (CASSANDRA-8930)
  * Allow roles cache to be invalidated (CASSANDRA-8967)
  * Upgrade Snappy (CASSANDRA-9063)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7f9ed0dd/src/java/org/apache/cassandra/cql3/functions/Functions.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/Functions.java b/src/java/org/apache/cassandra/cql3/functions/Functions.java
index bc0b9d9..7ac8039 100644
--- a/src/java/org/apache/cassandra/cql3/functions/Functions.java
+++ b/src/java/org/apache/cassandra/cql3/functions/Functions.java
@@ -19,9 +19,11 @@ package org.apache.cassandra.cql3.functions;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
-
-import com.google.common.collect.ArrayListMultimap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.apache.cassandra.config.Schema;
 import org.apache.cassandra.cql3.*;
@@ -39,7 +41,7 @@ public abstract class Functions
 
     private Functions() {}
 
-    private static final ArrayListMultimap<FunctionName, Function> declared = ArrayListMultimap.create();
+    private static final ConcurrentMap<FunctionName, List<Function>> declared = new ConcurrentHashMap<>();
 
     static
     {
@@ -85,20 +87,31 @@ public abstract class Functions
 
     private static void declare(Function fun)
     {
-        declared.put(fun.name(), fun);
+        synchronized (declared)
+        {
+            List<Function> functions = declared.get(fun.name());
+            if (functions == null)
+            {
+                functions = new CopyOnWriteArrayList<>();
+                List<Function> existing = declared.putIfAbsent(fun.name(), functions);
+                if (existing != null)
+                    functions = existing;
+            }
+            functions.add(fun);
+        }
     }
 
     public static ColumnSpecification makeArgSpec(String receiverKs, String receiverCf, Function fun, int i)
     {
         return new ColumnSpecification(receiverKs,
                                        receiverCf,
-                                       new ColumnIdentifier("arg" + i +  "(" + fun.name().toString().toLowerCase() + ")", true),
+                                       new ColumnIdentifier("arg" + i + '(' + fun.name().toString().toLowerCase() + ')', true),
                                        fun.argTypes().get(i));
     }
 
     public static int getOverloadCount(FunctionName name)
     {
-        return declared.get(name).size();
+        return find(name).size();
     }
 
     /**
@@ -142,13 +155,13 @@ public abstract class Functions
             // function name not fully qualified
             candidates = new ArrayList<>();
             // add 'SYSTEM' (native) candidates
-            candidates.addAll(declared.get(name.asNativeFunction()));
+            candidates.addAll(find(name.asNativeFunction()));
             // add 'current keyspace' candidates
-            candidates.addAll(declared.get(new FunctionName(keyspace, name.name)));
+            candidates.addAll(find(new FunctionName(keyspace, name.name)));
         }
         else
             // function name is fully qualified (keyspace + name)
-            candidates = declared.get(name);
+            candidates = find(name);
 
         if (candidates.isEmpty())
             return null;
@@ -191,13 +204,14 @@ public abstract class Functions
 
     public static List<Function> find(FunctionName name)
     {
-        return declared.get(name);
+        List<Function> functions = declared.get(name);
+        return functions != null ? functions : Collections.<Function>emptyList();
     }
 
     public static Function find(FunctionName name, List<AbstractType<?>> argTypes)
     {
         assert name.hasKeyspace() : "function name not fully qualified";
-        for (Function f : declared.get(name))
+        for (Function f : find(name))
         {
             if (typeEquals(f.argTypes(), argTypes))
                 return f;
@@ -282,11 +296,25 @@ public abstract class Functions
     }
 
     // Same remarks than for addFunction
-    public static void removeFunction(FunctionName name, List<AbstractType<?>> argsTypes)
+    public static void removeFunction(FunctionName name, List<AbstractType<?>> argTypes)
     {
-        Function old = find(name, argsTypes);
-        assert old != null && !old.isNative();
-        declared.remove(old.name(), old);
+        assert name.hasKeyspace() : "function name " + name + " not fully qualified";
+        synchronized (declared)
+        {
+            List<Function> functions = find(name);
+            for (int i = 0; i < functions.size(); i++)
+            {
+                Function f = functions.get(i);
+                if (!typeEquals(f.argTypes(), argTypes))
+                    continue;
+                assert !f.isNative();
+                functions.remove(i);
+                if (functions.isEmpty())
+                    declared.remove(name);
+                return;
+            }
+            assert false : "Function " + name + " not declared";
+        }
     }
 
     // Same remarks than for addFunction
@@ -299,15 +327,19 @@ public abstract class Functions
     public static List<Function> getReferencesTo(Function old)
     {
         List<Function> references = new ArrayList<>();
-        for (Function function : declared.values())
-            if (function.hasReferenceTo(old))
-                references.add(function);
+        for (List<Function> functions : declared.values())
+            for (Function function : functions)
+                if (function.hasReferenceTo(old))
+                    references.add(function);
         return references;
     }
 
     public static Collection<Function> all()
     {
-        return declared.values();
+        List<Function> all = new ArrayList<>();
+        for (List<Function> functions : declared.values())
+            all.addAll(functions);
+        return all;
     }
 
     public static boolean typeEquals(AbstractType<?> t1, AbstractType<?> t2)