From 74d9baf2d00b8f8073e5662f1a94267a366a5810 Mon Sep 17 00:00:00 2001
From: Steve Singer <ssinger@ca.afilias.info>
Date: Fri, 25 Jul 2014 11:35:59 -0400
Subject: [PATCH] Bug 345

The strtok_r on the node list was adding replacing the comma
with a NULL causing only 1 node to get inserted into sl_event.
This mean any nodes that where cascaded only saw 1 of the nodes
in the drop node list.

Call strtok_r on a copy of the list so it can safely be munged.

Also add in a DropNode cluster test to demonstrate test this issue
---
 clustertest/disorder/tests/DropNode.js       |   86 ++++++++++++++++++++++++++
 clustertest/disorder/tests/disorder_tests.js |    2 +
 src/slon/remote_worker.c                     |    5 +-
 3 files changed, 91 insertions(+), 2 deletions(-)
 create mode 100644 clustertest/disorder/tests/DropNode.js

diff --git a/clustertest/disorder/tests/DropNode.js b/clustertest/disorder/tests/DropNode.js
new file mode 100644
index 0000000..f8f094c
--- /dev/null
+++ b/clustertest/disorder/tests/DropNode.js
@@ -0,0 +1,86 @@
+/**
+ * Some tests of the DROP PATH command.
+ *
+ */
+
+coordinator.includeFile('disorder/tests/BasicTest.js');
+
+DropNode=function(coordinator,testResults) {
+	BasicTest.call(this,coordinator,testResults);
+	this.testDescription='This test exercises the DROP Node command\n';		
+}
+DropNode.prototype = new BasicTest();
+DropNode.prototype.constructor = DropNode;
+
+DropNode.prototype.runTest = function() {
+	this.testResults.newGroup("Drop Node");
+	//this.prepareDb(['db1','db2','db3','db4','db5']);
+	this.setupReplication();
+	
+	/**
+	 * Start the slons.
+	 */
+	var slonArray=[];
+	for(var idx=1; idx <= this.getNodeCount(); idx++) {
+		slonArray[idx-1] = this.coordinator.createSlonLauncher('db' + idx);
+		slonArray[idx-1].run();
+	}
+	
+	this.addTables();
+	this.subscribeSet(1,1,1,[2,3]);
+	if(this.testResults.getFailureCount()== 0) {
+		//No apparent errors.
+		this.subscribeSet(1,1,3,[4,5]);
+		
+	}
+	this.dropNode(1);
+	this.checkNodeDeleted(4,2);
+	this.checkNodeDeleted(4,5);
+	for(var idx=0; idx < this.getNodeCount(); idx++) {
+		
+		slonArray[idx].stop();
+		this.coordinator.join(slonArray[idx]);
+	}
+	
+	
+	
+	
+}
+
+DropNode.prototype.dropNode=function(event_node) {
+	this.coordinator.log('dropNode '   + event_node);
+	var slonikPreamble = this.getSlonikPreamble();
+	var slonikScript='echo \'DropNode.prototype.dropNode\';\n';
+        slonikScript += "drop node(id='2,5',event node=" + event_node +");\n"
+		+ 'wait for event(origin=' + event_node  + ',wait on=' + event_node 
+		+ ',confirmed=all);\n';
+	var slonik = this.coordinator.createSlonik('drop path', slonikPreamble, slonikScript);
+	slonik.run();
+	this.coordinator.join(slonik);
+	this.testResults.assertCheck('drop path returned as expected',slonik.getReturnCode(),
+								 0);
+	
+}
+
+
+DropNode.prototype.checkNodeDeleted=function(client,droppedNode) {
+	var connection = this.coordinator.createJdbcConnection('db' + client);
+	
+	var stat = connection.createStatement();
+	var rs=undefined;
+	try {
+		rs = stat.executeQuery("SELECT COUNT(*) FROM _" + this.getClusterName()
+				+ '.sl_node where no_id=' + droppedNode );
+		rs.next();
+		var count = rs.getInt(1);
+		this.testResults.assertCheck('node still exists' + droppedNode + ' on  ' + client
+				,count, 0);
+	}
+	finally {
+		if(rs != undefined) {
+			rs.close();
+		}
+		stat.close();
+		connection.close();
+	}
+}
\ No newline at end of file
diff --git a/clustertest/disorder/tests/disorder_tests.js b/clustertest/disorder/tests/disorder_tests.js
index 976cd21..6941a00 100644
--- a/clustertest/disorder/tests/disorder_tests.js
+++ b/clustertest/disorder/tests/disorder_tests.js
@@ -28,6 +28,7 @@ coordinator.includeFile('disorder/tests/WaitForTest.js');
 coordinator.includeFile('disorder/tests/MultinodeFailover.js');
 coordinator.includeFile('disorder/tests/Resubscribe.js');
 coordinator.includeFile('disorder/tests/SiteFailover.js');
+coordinator.includeFile('disorder/tests/DropNode.js');
 
 var tests = 
     [new EmptySet(coordinator,results)
@@ -57,6 +58,7 @@ var tests =
 	 ,new MultinodeFailover(coordinator,results)
 	 ,new Resubscribe(coordinator,results)
 	 ,new SiteFailover(coordinator,results)
+	 ,new DropNode(coordinator,results)
 	 //Below tests are known to fail.
 	 //,new UnsubscribeBeforeEnable(coordinator,results)
      //,new DropSet(coordinator,results) //fails bug 133
diff --git a/src/slon/remote_worker.c b/src/slon/remote_worker.c
index d9c340a..48e86fc 100644
--- a/src/slon/remote_worker.c
+++ b/src/slon/remote_worker.c
@@ -754,10 +754,10 @@ remoteWorkerThread_main(void *cdata)
 			}
 			else if (strcmp(event->ev_type, "DROP_NODE") == 0)
 			{
-				char *      node_list = event->ev_data1;
+				char *      node_list = strdup(event->ev_data1);
 				char * saveptr=NULL;
 				char * node_id=NULL;
-
+				
 				while((node_id=strtok_r(node_id==NULL ? node_list : NULL ,",",&saveptr))!=NULL)					
 				{
 					int			no_id = (int) strtol(node_id, NULL, 10);
@@ -798,6 +798,7 @@ remoteWorkerThread_main(void *cdata)
 						slon_retry();
 					}
 				}
+				free(node_list);
 
 				/*
 				 * this is a remote node. Arrange for daemon restart.
-- 
1.7.10.4

