Browse Source

Split remaining delta work on path boundaries

When an idle thread tries to steal work from a sibling's remaining
toSearch queue, always try to split along a path boundary. This
avoids missing delta opportunities in the current window of the
thread whose work is being taken.

The search order is reversed to walk further down the chain from
current position, avoiding the risk of splitting the list within
the path the thread is currently processing.

When selecting which thread to split from use an accurate estimate
of the size to be taken. This avoids selecting a thread that has
only one path remaining but may contain more pending entries than
another thread with several paths remaining.

As there is now a race condition where the straggling thread can
start the next path before the split can finish, the stealWork()
loop spins until it is able to acquire a split or there is only
one path remaining in the siblings.

Change-Id: Ib11ff99f90a4d9efab24bf4a85342cc63203dba5
tags/v3.0.0.201305080800-m7
Shawn Pearce 11 years ago
parent
commit
3b7924f403

+ 17
- 12
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java View File

@@ -76,23 +76,24 @@ final class DeltaTask implements Callable<Object> {
}

synchronized Slice stealWork() {
for (int attempts = 0; attempts < 2; attempts++) {
for (;;) {
DeltaTask maxTask = null;
Slice maxSlice = null;
int maxWork = 0;

for (DeltaTask task : tasks) {
int r = task.remaining();
if (maxWork < r) {
Slice s = task.remaining();
if (s != null && maxWork < s.size()) {
maxTask = task;
maxWork = r;
maxSlice = s;
maxWork = s.size();
}
}
if (maxTask == null)
return null;
Slice s = maxTask.stealWork();
if (s != null)
return s;
if (maxTask.tryStealWork(maxSlice))
return maxSlice;
}
return null;
}
}

@@ -104,6 +105,10 @@ final class DeltaTask implements Callable<Object> {
beginIndex = b;
endIndex = e;
}

final int size() {
return endIndex - beginIndex;
}
}

private final Block block;
@@ -131,13 +136,13 @@ final class DeltaTask implements Callable<Object> {
return null;
}

int remaining() {
Slice remaining() {
DeltaWindow d = dw;
return d != null ? d.remaining() : 0;
return d != null ? d.remaining() : null;
}

Slice stealWork() {
boolean tryStealWork(Slice s) {
DeltaWindow d = dw;
return d != null ? d.stealWork() : null;
return d != null ? d.tryStealWork(s) : false;
}
}

+ 27
- 16
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaWindow.java View File

@@ -115,26 +115,37 @@ final class DeltaWindow {
res = DeltaWindowEntry.createWindow(config.getDeltaSearchWindowSize());
}

synchronized int remaining() {
return end - cur;
}

synchronized DeltaTask.Slice stealWork() {
synchronized DeltaTask.Slice remaining() {
int e = end;
int n = (e - cur) >>> 1;
if (0 == n)
int halfRemaining = (e - cur) >>> 1;
if (0 == halfRemaining)
return null;

int t = e - n;
int h = toSearch[t].getPathHash();
while (cur < t) {
if (h == toSearch[t - 1].getPathHash())
t--;
else
break;
int split = e - halfRemaining;
int h = toSearch[split].getPathHash();
// Attempt to split on the next path after the 50% split point.
for (int n = split + 1; n < e; n++) {
if (h != toSearch[n].getPathHash())
return new DeltaTask.Slice(n, e);
}
end = t;
return new DeltaTask.Slice(t, e);

if (h != toSearch[cur].getPathHash()) {
// Try to split on the path before the 50% split point.
// Do not split the path currently being processed.
for (int p = split - 1; cur < p; p--) {
if (h != toSearch[p].getPathHash())
return new DeltaTask.Slice(p + 1, e);
}
}
return null;
}

synchronized boolean tryStealWork(DeltaTask.Slice s) {
if (s.beginIndex <= cur)
return false;
end = s.beginIndex;
return true;
}

void search() throws IOException {

Loading…
Cancel
Save