daemon: Make sure all the traverse children are terminated if traverse times out
authorAmitay Isaacs <amitay@gmail.com>
Tue, 22 Jan 2013 02:27:20 +0000 (13:27 +1100)
committerAmitay Isaacs <amitay@gmail.com>
Thu, 7 Feb 2013 02:48:37 +0000 (13:48 +1100)
When traverse times out, callback function is called with key and data set to
tdb_null.  This is also the way to signal end of traverse.  So if the traverse
times out, callback function treats it as traverse ended and frees state without
calling the destructor.

Keep track if the traverse timed out, so callback function can take appropriate
action for traverse timeout and traverse end.

Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Cherry-pick-from: 35da9a7c2a0f5e54e61588c3c3455f06ebc66822

server/ctdb_traverse.c

index 5ad374f098da6a8a498c7bfe3ec0640ebe2c7f45..8eac15a28f2d869d1d2ce72aa00c78d43781b759 100644 (file)
@@ -210,6 +210,7 @@ struct ctdb_traverse_all_handle {
        ctdb_traverse_fn_t callback;
        void *private_data;
        uint32_t null_count;
+       bool timedout;
 };
 
 /*
@@ -238,6 +239,7 @@ static void ctdb_traverse_all_timeout(struct event_context *ev, struct timed_eve
        DEBUG(DEBUG_ERR,(__location__ " Traverse all timeout on database:%s\n", state->ctdb_db->db_name));
        CTDB_INCREMENT_STAT(state->ctdb, timeouts.traverse);
 
+       state->timedout = true;
        state->callback(state->private_data, tdb_null, tdb_null);
 }
 
@@ -282,6 +284,7 @@ static struct ctdb_traverse_all_handle *ctdb_daemon_traverse_all(struct ctdb_db_
        state->callback     = callback;
        state->private_data = start_state;
        state->null_count   = 0;
+       state->timedout     = false;
        
        talloc_set_destructor(state, ctdb_traverse_all_destructor);
 
@@ -541,9 +544,14 @@ static void traverse_start_callback(void *p, TDB_DATA key, TDB_DATA data)
 
        ctdb_dispatch_message(state->ctdb, state->srvid, cdata);
        if (key.dsize == 0 && data.dsize == 0) {
-               /* end of traverse */
-               talloc_set_destructor(state, NULL);
-               talloc_free(state);
+               if (state->h->timedout) {
+                       /* timed out, send TRAVERSE_KILL control */
+                       talloc_free(state);
+               } else {
+                       /* end of traverse */
+                       talloc_set_destructor(state, NULL);
+                       talloc_free(state);
+               }
        }
 }