byzhang / leveldb

Automatically exported from code.google.com/p/leveldb
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

CompactRange() does not fully compact after WriteBatch is written #221

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
After writing data via a WriteBatch then deleting records, a single 
CompactRange(NULL, NULL) call does not appear to reclaim space as expected. 
Oddly, a second CompactRange(NULL, NULL) call right after the first does 
reclaim the space.

Repro:

First, the nominal case:

1. Open db
2. db->Put() 10 records, 1e6 bytes each
3. db->Delete() all 10 records
4. db->CompactRange(NULL, NULL)
Expect: Disk usage < 10kB
Actual: Disk usage < 10kB (i.e. this works as expected)

But now try with a WriteBatch:

1. Open db
2. Create a WriteBatch
3. batch->Put() 10 records, 1e6 bytes each
4. db->Write(WriteBatch)
5. db->Delete() all 10 records
6. Call db->CompactRange(NULL, NULL)
Expect: Disk usage < 10kB
Actual: Disk usage ~ 10MB (i.e. data was not compacted)

Finally, try calling CompactRange() twice:

1. Open db
2. Create a WriteBatch
3. batch->Put() 10 records, 1e6 bytes each
4. db->Write(WriteBatch)
5. db->Delete() all 10 records
6. db->CompactRange(NULL, NULL)
7. db->CompactRange(NULL, NULL)
Expect: Disk usage < 10kB
Actual: Disk usage < 10kB (i.e. data was compacted)

Failing test attached - it uses ftw() to measure disk usage, which may not be 
ideal.

Original issue reported on code.google.com by jsbell@chromium.org on 2 Jan 2014 at 11:03

Attachments:

GoogleCodeExporter commented 9 years ago

Original comment by dgrogan@chromium.org on 8 Jan 2014 at 1:10

GoogleCodeExporter commented 9 years ago
Peeking at this a bit. For whatever reason the thresholds in the attached test 
no longer work (or I was testing with a custom env). Change 
ASSERT_LT(SizeOnDisk(), 10e4); to ASSERT_LT(SizeOnDisk(), 10e5);

I'm still not sure what's going on, though it feels like leveldb is hitting an 
edge case. Dropping the number of records written in the non-batch test from 10 
to 9 makes it fail too. In that and the batch-with-single-compact case, 
max_level_with_files in DBImpl:CompactRange is 1, vs. 2 on 
batch-with-double-compact (on the second compact) or with 10 records in the 
non-batch case.

This may be related to the "we treat compactions from level-0 to level-1 
specially" note on http://leveldb.googlecode.com/git/doc/impl.html - if we 
don't have enough writes to push the database to level-1 then a full compaction 
is not done. But the first compaction pushes the database to level-1 then the 
second compaction avoids the special case.

Original comment by jsbell@chromium.org on 18 Feb 2014 at 11:20