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;
.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");
* 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;
}
} 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;
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];
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;
+ }
}