vacuum: move variable into scope of use in ctdb_process_delete_list()
[ctdb.git] / server / ctdb_vacuum.c
index 38e0c071f7034a748cc36cdf5a3cd3e77f505022..9611a1514ca1a6fc8465aeb7004e380a8345576a 100644 (file)
@@ -93,6 +93,7 @@ struct delete_record_data {
        struct ctdb_db_context *ctdb_db;
        struct ctdb_ltdb_header hdr;
        TDB_DATA key;
+       uint8_t keydata[1];
 };
 
 struct delete_records_list {
@@ -110,21 +111,22 @@ static int insert_delete_record_data_into_tree(struct ctdb_context *ctdb,
 {
        struct delete_record_data *dd;
        uint32_t hash;
+       size_t len;
 
-       dd = talloc_zero(tree, struct delete_record_data);
+       len = offsetof(struct delete_record_data, keydata) + key.dsize;
+
+       dd = (struct delete_record_data *)talloc_size(tree, len);
        if (dd == NULL) {
                DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
                return -1;
        }
+       talloc_set_name_const(dd, "struct delete_record_data");
 
        dd->ctdb      = ctdb;
        dd->ctdb_db   = ctdb_db;
        dd->key.dsize = key.dsize;
-       dd->key.dptr  = talloc_memdup(dd, key.dptr, key.dsize);
-       if (dd->key.dptr == NULL) {
-               DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
-               return -1;
-       }
+       dd->key.dptr  = dd->keydata;
+       memcpy(dd->keydata, key.dptr, key.dsize);
 
        dd->hdr = *hdr;
 
@@ -478,13 +480,19 @@ static int delete_record_traverse(void *param, void *data)
 
        tdb_data = tdb_fetch(ctdb_db->ltdb->tdb, dd->key);
        if (tdb_data.dsize < sizeof(struct ctdb_ltdb_header)) {
-               /* Does not exist or not a ctdb record. Skip. */
+               DEBUG(DEBUG_INFO, (__location__ ": record with hash [0x%08x] "
+                                  "on database db[%s] does not exist or is not"
+                                  " a ctdb-record.  skipping.\n",
+                                  hash, ctdb_db->db_name));
                vdata->delete_skipped++;
                goto done;
        }
 
        if (tdb_data.dsize > sizeof(struct ctdb_ltdb_header)) {
-               /* The record has been recycled (filled with data). Skip. */
+               DEBUG(DEBUG_INFO, (__location__ ": record with hash [0x%08x] "
+                                  "on database db[%s] has been recycled. "
+                                  "skipping.\n",
+                                  hash, ctdb_db->db_name));
                vdata->delete_skipped++;
                goto done;
        }
@@ -492,7 +500,10 @@ static int delete_record_traverse(void *param, void *data)
        header = (struct ctdb_ltdb_header *)tdb_data.dptr;
 
        if (header->dmaster != ctdb->pnn) {
-               /* The record has been migrated off the node. Skip. */
+               DEBUG(DEBUG_INFO, (__location__ ": record with hash [0x%08x] "
+                                  "on database db[%s] has been migrated away. "
+                                  "skipping.\n",
+                                  hash, ctdb_db->db_name));
                vdata->delete_skipped++;
                goto done;
        }
@@ -503,6 +514,11 @@ static int delete_record_traverse(void *param, void *data)
                 * The record has been migrated off the node and back again.
                 * But not requeued for deletion. Skip it.
                 */
+               DEBUG(DEBUG_INFO, (__location__ ": record with hash [0x%08x] "
+                                  "on database db[%s] seems to have been "
+                                  "migrated away and back again (with empty "
+                                  "data). skipping.\n",
+                                  hash, ctdb_db->db_name));
                vdata->delete_skipped++;
                goto done;
        }
@@ -510,7 +526,10 @@ static int delete_record_traverse(void *param, void *data)
        lmaster = ctdb_lmaster(ctdb_db->ctdb, &dd->key);
 
        if (lmaster != ctdb->pnn) {
-               /* we are not lmaster - strange */
+               DEBUG(DEBUG_INFO, (__location__ ": not lmaster for record in "
+                                  "delete list (key hash [0x%08x], db[%s]). "
+                                  "Strange! skipping.\n",
+                                  hash, ctdb_db->db_name));
                vdata->delete_skipped++;
                goto done;
        }
@@ -675,7 +694,7 @@ static int ctdb_process_vacuum_fetch_lists(struct ctdb_db_context *ctdb_db,
 }
 
 /**
- * Proces the delete list:
+ * Process the delete list:
  * Send the records to delete to all other nodes with the
  * try_delete_records control.
  */
@@ -684,135 +703,136 @@ static int ctdb_process_delete_list(struct ctdb_db_context *ctdb_db,
 {
        int ret, i;
        struct ctdb_context *ctdb = ctdb_db->ctdb;
+       struct delete_records_list *recs;
+       TDB_DATA indata, outdata;
+       struct ctdb_node_map *nodemap;
+       uint32_t *active_nodes;
+       int num_active_nodes;
+
+       if (vdata->delete_count == 0) {
+               return 0;
+       }
 
        vdata->delete_left = vdata->delete_count;
 
-       if (vdata->delete_count > 0) {
-               struct delete_records_list *recs;
-               TDB_DATA indata, outdata;
-               int32_t res;
-               struct ctdb_node_map *nodemap;
-               uint32_t *active_nodes;
-               int num_active_nodes;
+       recs = talloc_zero(vdata, struct delete_records_list);
+       if (recs == NULL) {
+               DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+               return -1;
+       }
+       recs->records = (struct ctdb_marshall_buffer *)
+               talloc_zero_size(vdata,
+                           offsetof(struct ctdb_marshall_buffer, data));
+       if (recs->records == NULL) {
+               DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
+               return -1;
+       }
+       recs->records->db_id = ctdb_db->db_id;
 
-               recs = talloc_zero(vdata, struct delete_records_list);
-               if (recs == NULL) {
-                       DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
-                       return -1;
-               }
-               recs->records = (struct ctdb_marshall_buffer *)
-                       talloc_zero_size(vdata,
-                                   offsetof(struct ctdb_marshall_buffer, data));
-               if (recs->records == NULL) {
-                       DEBUG(DEBUG_ERR,(__location__ " Out of memory\n"));
-                       return -1;
-               }
-               recs->records->db_id = ctdb_db->db_id;
+       /*
+        * traverse the tree of all records we want to delete and
+        * create a blob we can send to the other nodes.
+        */
+       trbt_traversearray32(vdata->delete_list, 1,
+                            delete_marshall_traverse, recs);
 
-               /*
-                * traverse the tree of all records we want to delete and
-                * create a blob we can send to the other nodes.
-                */
-               trbt_traversearray32(vdata->delete_list, 1,
-                                    delete_marshall_traverse, recs);
+       indata.dsize = talloc_get_size(recs->records);
+       indata.dptr  = (void *)recs->records;
 
-               indata.dsize = talloc_get_size(recs->records);
-               indata.dptr  = (void *)recs->records;
+       /*
+        * now tell all the active nodes to delete all these records
+        * (if possible)
+        */
 
-               /*
-                * now tell all the active nodes to delete all these records
-                * (if possible)
-                */
+       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(),
+                                  CTDB_CURRENT_NODE,
+                                  recs, /* talloc context */
+                                  &nodemap);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR,(__location__ " unable to get node map\n"));
+               return -1;
+       }
+
+       active_nodes = list_of_active_nodes(ctdb, nodemap,
+                                           nodemap, /* talloc context */
+                                           false /* include self */);
+       /* yuck! ;-) */
+       num_active_nodes = talloc_get_size(active_nodes)/sizeof(*active_nodes);
+
+       for (i = 0; i < num_active_nodes; i++) {
+               struct ctdb_marshall_buffer *records;
+               struct ctdb_rec_data *rec;
+               int32_t res;
 
-               ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(),
-                                          CTDB_CURRENT_NODE,
-                                          recs, /* talloc context */
-                                          &nodemap);
-               if (ret != 0) {
-                       DEBUG(DEBUG_ERR,(__location__ " unable to get node map\n"));
+               ret = ctdb_control(ctdb, active_nodes[i], 0,
+                               CTDB_CONTROL_TRY_DELETE_RECORDS, 0,
+                               indata, recs, &outdata, &res,
+                               NULL, NULL);
+               if (ret != 0 || res != 0) {
+                       DEBUG(DEBUG_ERR, ("Failed to delete records on "
+                                         "node %u: ret[%d] res[%d]\n",
+                                         active_nodes[i], ret, res));
                        return -1;
                }
 
-               active_nodes = list_of_active_nodes(ctdb, nodemap,
-                                                   nodemap, /* talloc context */
-                                                   false /* include self */);
-               /* yuck! ;-) */
-               num_active_nodes = talloc_get_size(active_nodes)/sizeof(*active_nodes);
-
-               for (i = 0; i < num_active_nodes; i++) {
-                       struct ctdb_marshall_buffer *records;
-                       struct ctdb_rec_data *rec;
-
-                       ret = ctdb_control(ctdb, active_nodes[i], 0,
-                                       CTDB_CONTROL_TRY_DELETE_RECORDS, 0,
-                                       indata, recs, &outdata, &res,
-                                       NULL, NULL);
-                       if (ret != 0 || res != 0) {
-                               DEBUG(DEBUG_ERR, ("Failed to delete records on "
-                                                 "node %u: ret[%d] res[%d]\n",
-                                                 active_nodes[i], ret, res));
+               /*
+                * outdata contains the list of records coming back
+                * from the node: These are the records that the
+                * remote node could not delete.
+                *
+                * NOTE: There is a problem here:
+                *
+                * When a node failed to delete the record, but
+                * others succeeded, we may have created gaps in the
+                * history of the record. Hence when a node dies, an
+                * closed file handle might be resurrected or an open
+                * file handle might be lost, leading to blocked access
+                * or data corruption.
+                *
+                * TODO: This needs to be fixed!
+                */
+               records = (struct ctdb_marshall_buffer *)outdata.dptr;
+               rec = (struct ctdb_rec_data *)&records->data[0];
+               while (records->count-- > 1) {
+                       TDB_DATA reckey, recdata;
+                       struct ctdb_ltdb_header *rechdr;
+                       struct delete_record_data *dd;
+
+                       reckey.dptr = &rec->data[0];
+                       reckey.dsize = rec->keylen;
+                       recdata.dptr = &rec->data[reckey.dsize];
+                       recdata.dsize = rec->datalen;
+
+                       if (recdata.dsize < sizeof(struct ctdb_ltdb_header)) {
+                               DEBUG(DEBUG_CRIT,(__location__ " bad ltdb record\n"));
                                return -1;
                        }
-
-                       /*
-                        * outdata contains the list of records coming back
-                        * from the node: These are the records that the
-                        * remote node could not delete.
-                        *
-                        * NOTE: There is a problem here:
-                        *
-                        * When a node failed to delete the record, but
-                        * others succeeded, we may have created gaps in the
-                        * history of the record. Hence when a node dies, an
-                        * closed file handle might be resurrected or an open
-                        * file handle might be lost, leading to blocked access
-                        * or data corruption.
-                        *
-                        * TODO: This needs to be fixed!
-                        */
-                       records = (struct ctdb_marshall_buffer *)outdata.dptr;
-                       rec = (struct ctdb_rec_data *)&records->data[0];
-                       while (records->count-- > 1) {
-                               TDB_DATA reckey, recdata;
-                               struct ctdb_ltdb_header *rechdr;
-                               struct delete_record_data *dd;
-
-                               reckey.dptr = &rec->data[0];
-                               reckey.dsize = rec->keylen;
-                               recdata.dptr = &rec->data[reckey.dsize];
-                               recdata.dsize = rec->datalen;
-
-                               if (recdata.dsize < sizeof(struct ctdb_ltdb_header)) {
-                                       DEBUG(DEBUG_CRIT,(__location__ " bad ltdb record\n"));
-                                       return -1;
-                               }
-                               rechdr = (struct ctdb_ltdb_header *)recdata.dptr;
-                               recdata.dptr += sizeof(*rechdr);
-                               recdata.dsize -= sizeof(*rechdr);
-
-                               dd = (struct delete_record_data *)trbt_lookup32(
-                                               vdata->delete_list,
-                                               (uint32_t)tdb_jenkins_hash(&reckey));
-                               if (dd != NULL) {
-                                       /*
-                                        * The other node could not delete the
-                                        * record and it is the first node that
-                                        * failed. So we should remove it from
-                                        * the tree and update statistics.
-                                        */
-                                       talloc_free(dd);
-                                       vdata->delete_remote_error++;
-                                       vdata->delete_left--;
-                               }
-
-                               rec = (struct ctdb_rec_data *)(rec->length + (uint8_t *)rec);
+                       rechdr = (struct ctdb_ltdb_header *)recdata.dptr;
+                       recdata.dptr += sizeof(*rechdr);
+                       recdata.dsize -= sizeof(*rechdr);
+
+                       dd = (struct delete_record_data *)trbt_lookup32(
+                                       vdata->delete_list,
+                                       (uint32_t)tdb_jenkins_hash(&reckey));
+                       if (dd != NULL) {
+                               /*
+                                * The other node could not delete the
+                                * record and it is the first node that
+                                * failed. So we should remove it from
+                                * the tree and update statistics.
+                                */
+                               talloc_free(dd);
+                               vdata->delete_remote_error++;
+                               vdata->delete_left--;
                        }
-               }
 
-               /* free nodemap and active_nodes */
-               talloc_free(nodemap);
+                       rec = (struct ctdb_rec_data *)(rec->length + (uint8_t *)rec);
+               }
        }
 
+       /* free nodemap and active_nodes */
+       talloc_free(nodemap);
+
        if (vdata->delete_left > 0) {
                /*
                 * The only records remaining in the tree are those