summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Adam <obnox@samba.org>2011-12-13 17:32:45 +0100
committerMichael Adam <obnox@samba.org>2011-12-23 17:39:05 +0100
commitc7b885c1c913b93a4a5f29b8dd01d1c3e49e060e (patch)
tree9257b494b99b109ebbe8fde0a1c84367ab034f58
parentaa04a6467989d2ac7eb9bc0661d1b0f5169fa0b8 (diff)
downloadsamba-c7b885c1c913b93a4a5f29b8dd01d1c3e49e060e.tar.gz
samba-c7b885c1c913b93a4a5f29b8dd01d1c3e49e060e.tar.xz
samba-c7b885c1c913b93a4a5f29b8dd01d1c3e49e060e.zip
vacuum: locally delete the records in the delete_tree that have be deleted remotely
This way, especially records added in the fast vacuuming runs are deleted direclty instead of being handed back to the repack run which will probably not hit because of the vacuum limit. (This used to be ctdb commit ea3e640a28178ddcb85285f4efec62ccba2483d9)
-rw-r--r--ctdb/server/ctdb_vacuum.c124
1 files changed, 116 insertions, 8 deletions
diff --git a/ctdb/server/ctdb_vacuum.c b/ctdb/server/ctdb_vacuum.c
index 24d5f35669..6e090ff246 100644
--- a/ctdb/server/ctdb_vacuum.c
+++ b/ctdb/server/ctdb_vacuum.c
@@ -82,6 +82,9 @@ struct vacuum_data {
uint32_t full_total;
uint32_t delete_left;
uint32_t delete_remote_error;
+ uint32_t delete_local_error;
+ uint32_t delete_deleted;
+ uint32_t delete_skipped;
};
/* this structure contains the information for one record to be deleted */
@@ -429,6 +432,107 @@ done:
}
/**
+ * Delete the records that we are lmaster and dmaster for and
+ * that could be deleted on all other nodes via the TRY_DELETE_RECORDS
+ * control.
+ */
+static int delete_record_traverse(void *param, void *data)
+{
+ struct delete_record_data *dd =
+ talloc_get_type(data, struct delete_record_data);
+ struct vacuum_data *vdata = talloc_get_type(param, struct vacuum_data);
+ struct ctdb_db_context *ctdb_db = dd->ctdb_db;
+ struct ctdb_context *ctdb = ctdb_db->ctdb;
+ int res;
+ struct ctdb_ltdb_header *header;
+ TDB_DATA tdb_data;
+ uint32_t lmaster;
+ bool deleted = false;
+
+ res = tdb_chainlock(ctdb_db->ltdb->tdb, dd->key);
+ if (res != 0) {
+ DEBUG(DEBUG_ERR, (__location__ " Error getting chainlock.\n"));
+ vdata->delete_local_error++;
+ return 0;
+ }
+
+ /*
+ * Verify that the record is still empty, its RSN has not
+ * changed and that we are still its lmaster and dmaster.
+ */
+
+ 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. */
+ vdata->delete_skipped++;
+ goto done;
+ }
+
+ if (tdb_data.dsize > sizeof(struct ctdb_ltdb_header)) {
+ /* The record has been recycled (filled with data). Skip. */
+ vdata->delete_skipped++;
+ goto done;
+ }
+
+ header = (struct ctdb_ltdb_header *)tdb_data.dptr;
+
+ if (header->dmaster != ctdb->pnn) {
+ /* The record has been migrated off the node. Skip. */
+ vdata->delete_skipped++;
+ goto done;
+ }
+
+
+ if (header->rsn != dd->hdr.rsn) {
+ /*
+ * The record has been migrated off the node and back again.
+ * But not requeued for deletion. Skip it.
+ */
+ vdata->delete_skipped++;
+ goto done;
+ }
+
+ lmaster = ctdb_lmaster(ctdb_db->ctdb, &dd->key);
+
+ if (lmaster != ctdb->pnn) {
+ /* we are not lmaster - strange */
+ vdata->delete_skipped++;
+ goto done;
+ }
+
+ res = tdb_delete(ctdb_db->ltdb->tdb, dd->key);
+
+ if (res != 0) {
+ DEBUG(DEBUG_ERR,
+ (__location__ " Error deleting record from local "
+ "data base.\n"));
+ vdata->delete_local_error++;
+ goto done;
+ }
+
+ deleted = true;
+
+done:
+ if (tdb_data.dptr != NULL) {
+ free(tdb_data.dptr);
+ }
+
+ tdb_chainunlock(ctdb_db->ltdb->tdb, dd->key);
+
+ if (deleted) {
+ /*
+ * successfully deleted the record locally.
+ * remove it from the list and update statistics.
+ */
+ talloc_free(dd);
+ vdata->delete_deleted++;
+ vdata->delete_left--;
+ }
+
+ return 0;
+}
+
+/**
* Vacuum a DB:
* - Always do the fast vacuuming run, which traverses
* the in-memory delete queue: these records have been
@@ -501,6 +605,9 @@ static int ctdb_vacuum_db(struct ctdb_db_context *ctdb_db,
vdata->delete_count = 0;
vdata->delete_left = 0;
vdata->delete_remote_error = 0;
+ vdata->delete_local_error = 0;
+ vdata->delete_skipped = 0;
+ vdata->delete_deleted = 0;
/* the list needs to be of length num_nodes */
vdata->list = talloc_array(vdata, struct ctdb_marshall_buffer *, ctdb->num_nodes);
@@ -722,16 +829,17 @@ static int ctdb_vacuum_db(struct ctdb_db_context *ctdb_db,
/* free nodemap and active_nodes */
talloc_free(nodemap);
+ }
- /*
- * The only records remaining in the tree would be those
- * records where all other nodes could successfully
- * delete them, so we can safely delete them on the
- * lmaster as well. Deletion implictely happens while
- * we repack the database. The repack algorithm revisits
- * the tree in order to find the records that don't need
- * to be copied / repacked.
+ if (vdata->delete_left > 0) {
+ /*
+ * The only records remaining in the tree are those
+ * records which all other nodes could successfully
+ * delete, so we can safely delete them on the
+ * lmaster as well.
*/
+ trbt_traversearray32(vdata->delete_tree, 1,
+ delete_record_traverse, vdata);
}
/* this ensures we run our event queue */