Merge "Split note leaf buckets at 256 elements"

This commit is contained in:
Chris Aniszczyk 2010-11-13 12:37:30 -05:00 committed by Code Review
commit 1b3abe75f8
4 changed files with 99 additions and 7 deletions

View File

@ -47,6 +47,7 @@
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.MutableObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
@ -361,6 +362,46 @@ public void testEditFanout2_38() throws Exception {
.forPath(reader, "zoo-animals.txt", n.getTree()).getObjectId(0));
}
public void testLeafSplitsWhenFull() throws Exception {
RevBlob data1 = tr.blob("data1");
MutableObjectId idBuf = new MutableObjectId();
RevCommit r = tr.commit() //
.add(data1.name(), data1) //
.create();
tr.parseBody(r);
NoteMap map = NoteMap.read(reader, r);
for (int i = 0; i < 254; i++) {
idBuf.setByte(Constants.OBJECT_ID_LENGTH - 1, i);
map.set(idBuf, data1);
}
RevCommit n = commitNoteMap(map);
TreeWalk tw = new TreeWalk(reader);
tw.reset(n.getTree());
while (tw.next())
assertFalse("no fan-out subtree", tw.isSubtree());
for (int i = 254; i < 256; i++) {
idBuf.setByte(Constants.OBJECT_ID_LENGTH - 1, i);
map.set(idBuf, data1);
}
idBuf.setByte(Constants.OBJECT_ID_LENGTH - 2, 1);
map.set(idBuf, data1);
n = commitNoteMap(map);
// The 00 bucket is fully split.
String path = fanout(38, idBuf.name());
tw = TreeWalk.forPath(reader, path, n.getTree());
assertNotNull("has " + path, tw);
// The other bucket is not.
path = fanout(2, data1.name());
tw = TreeWalk.forPath(reader, path, n.getTree());
assertNotNull("has " + path, tw);
}
public void testRemoveDeletesTreeFanout2_38() throws Exception {
RevBlob a = tr.blob("a");
RevBlob data1 = tr.blob("data1");

View File

@ -228,6 +228,24 @@ private int treeSize() {
return sz;
}
@Override
InMemoryNoteBucket append(Note note) {
int cell = cell(note);
InMemoryNoteBucket b = (InMemoryNoteBucket) table[cell];
if (b == null) {
LeafBucket n = new LeafBucket(prefixLen + 2);
table[cell] = n.append(note);
cnt++;
} else {
InMemoryNoteBucket n = b.append(note);
if (n != b)
table[cell] = n;
}
return this;
}
private int cell(AnyObjectId id) {
return id.getByte(prefixLen >> 1);
}

View File

@ -68,4 +68,6 @@ abstract class InMemoryNoteBucket extends NoteBucket {
InMemoryNoteBucket(int prefixLen) {
this.prefixLen = prefixLen;
}
abstract InMemoryNoteBucket append(Note note);
}

View File

@ -73,6 +73,8 @@
* A LeafBucket must be parsed from a tree object by {@link NoteParser}.
*/
class LeafBucket extends InMemoryNoteBucket {
static final int MAX_SIZE = 256;
/** All note blobs in this bucket, sorted sequentially. */
private Note[] notes;
@ -142,13 +144,18 @@ InMemoryNoteBucket set(AnyObjectId noteOn, AnyObjectId noteData,
}
} else if (noteData != null) {
growIfFull();
p = -(p + 1);
if (p < cnt)
System.arraycopy(notes, p, notes, p + 1, cnt - p);
notes[p] = new Note(noteOn, noteData.copy());
cnt++;
return this;
if (shouldSplit()) {
return split().set(noteOn, noteData, or);
} else {
growIfFull();
p = -(p + 1);
if (p < cnt)
System.arraycopy(notes, p, notes, p + 1, cnt - p);
notes[p] = new Note(noteOn, noteData.copy());
cnt++;
return this;
}
} else {
return this;
@ -193,6 +200,18 @@ void parseOneEntry(AnyObjectId noteOn, AnyObjectId noteData) {
notes[cnt++] = new Note(noteOn, noteData.copy());
}
@Override
InMemoryNoteBucket append(Note note) {
if (shouldSplit()) {
return split().append(note);
} else {
growIfFull();
notes[cnt++] = note;
return this;
}
}
private void growIfFull() {
if (notes.length == cnt) {
Note[] n = new Note[notes.length * 2];
@ -200,4 +219,16 @@ private void growIfFull() {
notes = n;
}
}
private boolean shouldSplit() {
return MAX_SIZE <= cnt && prefixLen + 2 < OBJECT_ID_STRING_LENGTH;
}
private InMemoryNoteBucket split() {
FanoutBucket n = new FanoutBucket(prefixLen);
for (int i = 0; i < cnt; i++)
n.append(notes[i]);
n.nonNotes = nonNotes;
return n;
}
}