You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2009/11/26 16:56:46 UTC

svn commit: r884612 - in /qpid/trunk/qpid: cpp/src/qpid/cluster/Cluster.cpp cpp/src/qpid/cluster/InitialStatusMap.cpp cpp/src/qpid/cluster/StoreStatus.cpp cpp/src/qpid/cluster/StoreStatus.h cpp/src/tests/cluster_tests.py python/qpid/brokertest.py

Author: aconway
Date: Thu Nov 26 15:56:46 2009
New Revision: 884612

URL: http://svn.apache.org/viewvc?rev=884612&view=rev
Log:
Cluster consistency: check for no clean store condition.

Modified:
    qpid/trunk/qpid/cpp/src/qpid/cluster/Cluster.cpp
    qpid/trunk/qpid/cpp/src/qpid/cluster/InitialStatusMap.cpp
    qpid/trunk/qpid/cpp/src/qpid/cluster/StoreStatus.cpp
    qpid/trunk/qpid/cpp/src/qpid/cluster/StoreStatus.h
    qpid/trunk/qpid/cpp/src/tests/cluster_tests.py
    qpid/trunk/qpid/python/qpid/brokertest.py

Modified: qpid/trunk/qpid/cpp/src/qpid/cluster/Cluster.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qpid/cluster/Cluster.cpp?rev=884612&r1=884611&r2=884612&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/qpid/cluster/Cluster.cpp (original)
+++ qpid/trunk/qpid/cpp/src/qpid/cluster/Cluster.cpp Thu Nov 26 15:56:46 2009
@@ -260,6 +260,7 @@
         store.load();
         if (store.getClusterId())
             clusterId = store.getClusterId(); // Use stored ID if there is one.
+        QPID_LOG(notice, "Cluster store state: " << store)
     }
 
     cpg.join(name);

Modified: qpid/trunk/qpid/cpp/src/qpid/cluster/InitialStatusMap.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qpid/cluster/InitialStatusMap.cpp?rev=884612&r1=884611&r2=884612&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/qpid/cluster/InitialStatusMap.cpp (original)
+++ qpid/trunk/qpid/cpp/src/qpid/cluster/InitialStatusMap.cpp Thu Nov 26 15:56:46 2009
@@ -148,39 +148,49 @@
         return map.begin()->second->getClusterId(); // Youngest newcomer in node-id order
 }
 
+void checkId(Uuid& expect, const Uuid& actual, const string& msg) {
+    if (!expect) expect = actual;
+    assert(expect);
+    if (expect != actual)
+        throw Exception(msg);
+}
+
 void InitialStatusMap::checkConsistent() {
     assert(isComplete());
-    bool persistent = (map.begin()->second->getStoreState() != STORE_STATE_NO_STORE);
+    int clean = 0;
+    int dirty = 0;
+    int empty = 0;
+    int none = 0;
+    int active = 0;
     Uuid clusterId;
+    Uuid shutdownId;
+
     for (Map::iterator i = map.begin(); i != map.end(); ++i) {
-        // Must not mix transient and persistent members.
-        if (persistent != (i->second->getStoreState() != STORE_STATE_NO_STORE))
-            throw Exception("Mixing transient and persistent brokers in a cluster");
-        // Members with non-empty stores must have same cluster-id
+        if (i->second->getActive()) ++active;
         switch (i->second->getStoreState()) {
-          case STORE_STATE_NO_STORE:
-          case STORE_STATE_EMPTY_STORE:
-            break;               
+          case STORE_STATE_NO_STORE: ++none; break;
+          case STORE_STATE_EMPTY_STORE: ++empty; break;
           case STORE_STATE_DIRTY_STORE:
+            ++dirty;
+            checkId(clusterId, i->second->getClusterId(),
+                    "Cluster-ID mismatch. Stores belong to different clusters.");
+            break;
           case STORE_STATE_CLEAN_STORE:
-            if (!clusterId) clusterId = i->second->getClusterId();
-            assert(clusterId);
-            if (clusterId != i->second->getClusterId())
-                throw Exception("Cluster-id mismatch, brokers belonged to different clusters.");
-        }
-    }
-    // If this is a newly forming cluster, clean stores must have same shutdown-id
-    if (find_if(map.begin(), map.end(), &isActive) == map.end()) {
-        Uuid shutdownId;
-        for (Map::iterator i = map.begin(); i != map.end(); ++i) {
-            if (i->second->getStoreState() == STORE_STATE_CLEAN_STORE) {
-                if (!shutdownId) shutdownId = i->second->getShutdownId();
-                assert(shutdownId);
-                if (shutdownId != i->second->getShutdownId())
-                    throw Exception("Shutdown-id mismatch, brokers were not shut down together.");
-            }
+            ++clean;
+            checkId(clusterId, i->second->getClusterId(),
+                    "Cluster-ID mismatch. Stores belong to different clusters.");
+            checkId(shutdownId, i->second->getShutdownId(),
+                    "Shutdown-ID mismatch. Stores were not shut down together");
+            break;
         }
     }
+    // Can't mix transient and persistent members.
+    if (none && (clean+dirty+empty))
+        throw Exception("Mixing transient and persistent brokers in a cluster");
+    // If there are no active members and there are dirty stores there
+    // must be at least one clean store.
+    if (!active && dirty && !clean)
+        throw Exception("Cannot recover, no clean store");
 }
 
 

Modified: qpid/trunk/qpid/cpp/src/qpid/cluster/StoreStatus.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qpid/cluster/StoreStatus.cpp?rev=884612&r1=884611&r2=884612&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/qpid/cluster/StoreStatus.cpp (original)
+++ qpid/trunk/qpid/cpp/src/qpid/cluster/StoreStatus.cpp Thu Nov 26 15:56:46 2009
@@ -31,6 +31,7 @@
 using framing::Uuid;
 using namespace framing::cluster;
 using namespace boost::filesystem;
+using std::ostream;
 
 StoreStatus::StoreStatus(const std::string& d)
     : state(STORE_STATE_NO_STORE), dataDir(d)
@@ -90,5 +91,20 @@
     save();
 }
 
+ostream& operator<<(ostream& o, const StoreStatus& s) {
+    switch (s.getState()) {
+      case STORE_STATE_NO_STORE: o << "no store"; break;
+      case STORE_STATE_EMPTY_STORE: o << "empty store"; break;
+      case STORE_STATE_DIRTY_STORE:
+        o << "dirty store, cluster-id=" << s.getClusterId();
+        break;
+      case STORE_STATE_CLEAN_STORE:
+        o << "clean store, cluster-id=" << s.getClusterId()
+          << " shutdown-id=" << s.getShutdownId();
+        break;
+    }
+    return o;
+}
+
 }} // namespace qpid::cluster
 

Modified: qpid/trunk/qpid/cpp/src/qpid/cluster/StoreStatus.h
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qpid/cluster/StoreStatus.h?rev=884612&r1=884611&r2=884612&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/qpid/cluster/StoreStatus.h (original)
+++ qpid/trunk/qpid/cpp/src/qpid/cluster/StoreStatus.h Thu Nov 26 15:56:46 2009
@@ -24,6 +24,7 @@
 
 #include "qpid/framing/Uuid.h"
 #include "qpid/framing/enum.h"
+#include <iosfwd>
 
 namespace qpid {
 namespace cluster {
@@ -56,6 +57,8 @@
     Uuid clusterId, shutdownId;
     std::string dataDir;
 };
+
+std::ostream& operator<<(std::ostream&, const StoreStatus&);
 }} // namespace qpid::cluster
 
 #endif  /*!QPID_CLUSTER_STORESTATE_H*/

Modified: qpid/trunk/qpid/cpp/src/tests/cluster_tests.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/tests/cluster_tests.py?rev=884612&r1=884611&r2=884612&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/tests/cluster_tests.py (original)
+++ qpid/trunk/qpid/cpp/src/tests/cluster_tests.py Thu Nov 26 15:56:46 2009
@@ -18,7 +18,7 @@
 # under the License.
 #
 
-import os, signal, sys, time, imp
+import os, signal, sys, time, imp, re
 from qpid import datatypes, messaging
 from qpid.brokertest import *
 from qpid.harness import Skipped
@@ -189,4 +189,17 @@
         a = cluster.start("a", expect=EXPECT_EXIT_FAIL, wait=False)
         b = cluster.start("b", expect=EXPECT_EXIT_FAIL, wait=False)
 
-
+    def test_total_failure(self):
+        # Verify we abort with sutiable error message if no clean stores.
+        cluster = self.cluster(0, args=self.args()+["--cluster-size=2"])
+        a = cluster.start("a", expect=EXPECT_EXIT_FAIL, wait=False)
+        b = cluster.start("b", expect=EXPECT_EXIT_FAIL, wait=True)
+        a.kill()
+        b.kill()
+        a = cluster.start("a", expect=EXPECT_EXIT_FAIL, wait=False)
+        b = cluster.start("b", expect=EXPECT_EXIT_FAIL, wait=False)
+        assert a.wait() != 0
+        assert b.wait() != 0
+        msg = re.compile("critical.*no clean store")
+        assert msg.search(file(a.log).read())
+        assert msg.search(file(b.log).read())

Modified: qpid/trunk/qpid/python/qpid/brokertest.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/python/qpid/brokertest.py?rev=884612&r1=884611&r2=884612&view=diff
==============================================================================
--- qpid/trunk/qpid/python/qpid/brokertest.py (original)
+++ qpid/trunk/qpid/python/qpid/brokertest.py Thu Nov 26 15:56:46 2009
@@ -157,8 +157,8 @@
         if (self._port is None):
             try: self._port = int(self.stdout.readline())
             except ValueError, e:
-                raise Exception("Can't get port for broker %s (%s)" %
-                                (self.name, self.pname))
+                raise Exception("Can't get port for broker %s (%s)\n    %s" %
+                                (self.name, self.pname, file(self.log).readlines()[-1]))
         return self._port
 
     def unexpected(self,msg):



---------------------------------------------------------------------
Apache Qpid - AMQP Messaging Implementation
Project:      http://qpid.apache.org
Use/Interact: mailto:commits-subscribe@qpid.apache.org