Browse Source

Fix edge-case where `reserve` pushes an adjacent block.

Previously, `push` might oversee a possible merge and thus increasing fragmentation. This commit (by @nilset) fixes that.

- Ignore slow tests.
ticki 8 years ago
parent
commit
2b7af3702d
2 changed files with 11 additions and 4 deletions
  1. 10 4
      src/bookkeeper.rs
  2. 1 0
      tests/join.rs

+ 10 - 4
src/bookkeeper.rs

@@ -655,11 +655,17 @@ pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
             // Merging failed. Note that trailing empty blocks are not allowed, hence the last block is
             // the only non-empty candidate which may be adjacent to `block`.
 
-            // Mark it free and push.
-            let res = self.pool.push(block.mark_free());
+            // Check again that pushing is correct.
+            if self.pool.is_empty() || &block > self.pool.last().unwrap() {
+                // We push.
+                let res = self.pool.push(block);
 
-            // Make some assertions.
-            debug_assert!(res.is_ok(), "Push failed (buffer full).");
+                // Make some assertions.
+                debug_assert!(res.is_ok(), "Push failed (buffer full).");
+            } else {
+                // Can't push because reserve changed the end of the pool.
+                self.free(block);
+            }
         }
 
         // Check consistency.

+ 1 - 0
tests/join.rs

@@ -5,6 +5,7 @@ mod util;
 use std::thread;
 
 #[test]
+#[ignore]
 fn join_thread() {
     util::multiply(|| {
         for i in 0..0xFFF {