Rev 697: prevent O(n^2) behaviour for traverse after large numbers of deletes in http://samba.org/~tridge/ctdb

tridge at samba.org tridge at samba.org
Fri Jan 4 01:12:04 GMT 2008


------------------------------------------------------------
revno: 697
revision-id:tridge at samba.org-20080104011202-8236ox1e39q8irrf
parent: tridge at samba.org-20080104011129-bsprbhxtczom25gx
committer: Andrew Tridgell <tridge at samba.org>
branch nick: tridge.kantana
timestamp: Fri 2008-01-04 12:12:02 +1100
message:
  prevent O(n^2) behaviour for traverse after large numbers of deletes
modified:
  lib/tdb/common/freelist.c      freelist.c-20070220022425-m1wibgjq7n5hahs6-4
=== modified file 'lib/tdb/common/freelist.c'
--- a/lib/tdb/common/freelist.c	2008-01-02 01:04:07 +0000
+++ b/lib/tdb/common/freelist.c	2008-01-04 01:12:02 +0000
@@ -105,6 +105,10 @@
 		goto fail;
 	}
 
+#if 0
+	/* (tridge) disable 'right' merges for now as they give rise to a O(n^2) behaviour during
+	   traverse which is freeing old dead records */
+
 	/* Look right first (I'm an Australian, dammit) */
 	right = offset + sizeof(*rec) + rec->rec_len;
 	if (right + sizeof(*rec) <= tdb->map_size) {
@@ -124,6 +128,7 @@
 			rec->rec_len += sizeof(r) + r.rec_len;
 		}
 	}
+#endif
 
 left:
 	/* Look left */
@@ -153,6 +158,23 @@
 
 		/* If it's free, expand to include it. */
 		if (l.magic == TDB_FREE_MAGIC) {
+#if 1
+			/* we now merge the new record into the left record, rather than the other 
+			   way around. This makes the operation O(1) instead of O(n). This change
+			   prevents traverse from being O(n^2) after a lot of deletes */
+			l.rec_len += sizeof(*rec) + rec->rec_len;
+			if (tdb_rec_write(tdb, left, &l) == -1) {
+				TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_left failed at %u\n", left));
+				goto fail;
+			}
+			if (update_tailer(tdb, left, &l) == -1) {
+				TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: update_tailer failed at %u\n", offset));
+				goto fail;
+			}
+			/* we're done. */
+			tdb_unlock(tdb, -1, F_WRLCK);
+			return 0;			
+#else
 			if (remove_from_freelist(tdb, left, l.next) == -1) {
 				TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_free: left free failed at %u\n", left));
 				goto update;
@@ -160,6 +182,7 @@
 				offset = left;
 				rec->rec_len += leftsize;
 			}
+#endif
 		}
 	}
 



More information about the samba-cvs mailing list