ctdb-call: Drop all deferred requests from older generation
authorAmitay Isaacs <amitay@gmail.com>
Tue, 2 Sep 2014 06:10:20 +0000 (16:10 +1000)
committerMartin Schwenke <martins@samba.org>
Fri, 5 Sep 2014 07:30:50 +0000 (09:30 +0200)
Deferring packets has a nasty interaction with recovery.  All deferred
packets must be dropped when recovery happens, since those packets are
tracked as pending requests and will be re-sent with new generation.

Signed-off-by: Amitay Isaacs <amitay@gmail.com>
Reviewed-by: Martin Schwenke <martin@meltin.net>
Autobuild-User(master): Martin Schwenke <martins@samba.org>
Autobuild-Date(master): Fri Sep  5 09:30:50 CEST 2014 on sn-devel-104

ctdb/server/ctdb_call.c

index 956b3e871176743c150663a624819d714c66acd5..391dfb1ab5a6f0e6474edcf82b8cde59b8132b3d 100644 (file)
@@ -416,6 +416,8 @@ struct dmaster_defer_call {
 };
 
 struct dmaster_defer_queue {
+       struct ctdb_context *ctdb;
+       uint32_t generation;
        struct dmaster_defer_call *deferred_calls;
 };
 
@@ -433,6 +435,11 @@ static void dmaster_defer_reprocess(struct tevent_context *ev,
 
 static int dmaster_defer_queue_destructor(struct dmaster_defer_queue *ddq)
 {
+       /* Ignore requests, if database recovery happens in-between. */
+       if (ddq->generation != ddq->ctdb->vnn_map->generation) {
+               return 0;
+       }
+
        while (ddq->deferred_calls != NULL) {
                struct dmaster_defer_call *call = ddq->deferred_calls;
 
@@ -483,6 +490,8 @@ static int dmaster_defer_setup(struct ctdb_db_context *ctdb_db,
                talloc_free(k);
                return -1;
        }
+       ddq->ctdb = ctdb_db->ctdb;
+       ddq->generation = hdr->generation;
        ddq->deferred_calls = NULL;
 
        trbt_insertarray32_callback(ctdb_db->defer_dmaster, k[0], k,
@@ -515,6 +524,12 @@ static int dmaster_defer_add(struct ctdb_db_context *ctdb_db,
 
        talloc_free(k);
 
+       if (ddq->generation != hdr->generation) {
+               talloc_set_destructor(ddq, NULL);
+               talloc_free(ddq);
+               return -1;
+       }
+
        call = talloc(ddq, struct dmaster_defer_call);
        if (call == NULL) {
                DEBUG(DEBUG_ERR, ("Failed to allocate dmaster defer call\n"));