summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src
diff options
context:
space:
mode:
authorShawn Pearce <spearce@spearce.org>2013-04-11 15:32:07 -0700
committerShawn Pearce <spearce@spearce.org>2013-04-12 12:03:38 -0700
commit3b7924f403afea45b2c7464d88b0b10f8f9c656a (patch)
tree167223ce8341e892ea1e72bf31971a927a93b92b /org.eclipse.jgit/src
parentaf33a911d0e5a4ee3a5e520b36e1b565c84df6e5 (diff)
downloadjgit-3b7924f403afea45b2c7464d88b0b10f8f9c656a.tar.gz
jgit-3b7924f403afea45b2c7464d88b0b10f8f9c656a.zip
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
Diffstat (limited to 'org.eclipse.jgit/src')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java29
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaWindow.java43
2 files changed, 44 insertions, 28 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java
index 218696eef6..cc212fb818 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java
@@ -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;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaWindow.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaWindow.java
index 2eb1daf748..7688da395b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaWindow.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaWindow.java
@@ -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 {