Merge "Split note leaf buckets at 256 elements"
This commit is contained in:
commit
1b3abe75f8
|
@ -47,6 +47,7 @@
|
||||||
|
|
||||||
import org.eclipse.jgit.junit.TestRepository;
|
import org.eclipse.jgit.junit.TestRepository;
|
||||||
import org.eclipse.jgit.lib.CommitBuilder;
|
import org.eclipse.jgit.lib.CommitBuilder;
|
||||||
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.MutableObjectId;
|
import org.eclipse.jgit.lib.MutableObjectId;
|
||||||
import org.eclipse.jgit.lib.ObjectInserter;
|
import org.eclipse.jgit.lib.ObjectInserter;
|
||||||
import org.eclipse.jgit.lib.ObjectReader;
|
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));
|
.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 {
|
public void testRemoveDeletesTreeFanout2_38() throws Exception {
|
||||||
RevBlob a = tr.blob("a");
|
RevBlob a = tr.blob("a");
|
||||||
RevBlob data1 = tr.blob("data1");
|
RevBlob data1 = tr.blob("data1");
|
||||||
|
|
|
@ -228,6 +228,24 @@ private int treeSize() {
|
||||||
return sz;
|
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) {
|
private int cell(AnyObjectId id) {
|
||||||
return id.getByte(prefixLen >> 1);
|
return id.getByte(prefixLen >> 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,4 +68,6 @@ abstract class InMemoryNoteBucket extends NoteBucket {
|
||||||
InMemoryNoteBucket(int prefixLen) {
|
InMemoryNoteBucket(int prefixLen) {
|
||||||
this.prefixLen = prefixLen;
|
this.prefixLen = prefixLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract InMemoryNoteBucket append(Note note);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,8 @@
|
||||||
* A LeafBucket must be parsed from a tree object by {@link NoteParser}.
|
* A LeafBucket must be parsed from a tree object by {@link NoteParser}.
|
||||||
*/
|
*/
|
||||||
class LeafBucket extends InMemoryNoteBucket {
|
class LeafBucket extends InMemoryNoteBucket {
|
||||||
|
static final int MAX_SIZE = 256;
|
||||||
|
|
||||||
/** All note blobs in this bucket, sorted sequentially. */
|
/** All note blobs in this bucket, sorted sequentially. */
|
||||||
private Note[] notes;
|
private Note[] notes;
|
||||||
|
|
||||||
|
@ -142,13 +144,18 @@ InMemoryNoteBucket set(AnyObjectId noteOn, AnyObjectId noteData,
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (noteData != null) {
|
} else if (noteData != null) {
|
||||||
growIfFull();
|
if (shouldSplit()) {
|
||||||
p = -(p + 1);
|
return split().set(noteOn, noteData, or);
|
||||||
if (p < cnt)
|
|
||||||
System.arraycopy(notes, p, notes, p + 1, cnt - p);
|
} else {
|
||||||
notes[p] = new Note(noteOn, noteData.copy());
|
growIfFull();
|
||||||
cnt++;
|
p = -(p + 1);
|
||||||
return this;
|
if (p < cnt)
|
||||||
|
System.arraycopy(notes, p, notes, p + 1, cnt - p);
|
||||||
|
notes[p] = new Note(noteOn, noteData.copy());
|
||||||
|
cnt++;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return this;
|
return this;
|
||||||
|
@ -193,6 +200,18 @@ void parseOneEntry(AnyObjectId noteOn, AnyObjectId noteData) {
|
||||||
notes[cnt++] = new Note(noteOn, noteData.copy());
|
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() {
|
private void growIfFull() {
|
||||||
if (notes.length == cnt) {
|
if (notes.length == cnt) {
|
||||||
Note[] n = new Note[notes.length * 2];
|
Note[] n = new Note[notes.length * 2];
|
||||||
|
@ -200,4 +219,16 @@ private void growIfFull() {
|
||||||
notes = n;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue