RepoSequence: Add method to get IDs in bulk

When we know a caller is going to need more than batchSize IDs, we can
request them all in a single increment rather than requiring multiple
writes to the sequence ref.

Change-Id: Iebf09e2d144c021797b70ac6e877894886521167
This commit is contained in:
Dave Borowitz
2016-07-22 14:28:24 -04:00
parent 08de3c852b
commit 2460b00acd
2 changed files with 112 additions and 7 deletions

View File

@@ -23,6 +23,7 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CharMatcher;
import com.google.common.base.Predicates;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Ints;
import com.google.common.util.concurrent.Runnables;
import com.google.gerrit.common.Nullable;
@@ -47,6 +48,8 @@ import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevWalk;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@@ -135,7 +138,7 @@ public class RepoSequence {
counterLock.lock();
try {
if (counter >= limit) {
acquire();
acquire(batchSize);
}
return counter++;
} finally {
@@ -143,6 +146,30 @@ public class RepoSequence {
}
}
public ImmutableList<Integer> next(int count) throws OrmException {
if (count == 0) {
return ImmutableList.of();
}
checkArgument(count > 0, "count is negative: %s", count);
counterLock.lock();
try {
List<Integer> ids = new ArrayList<>(count);
while (counter < limit) {
ids.add(counter++);
if (ids.size() == count) {
return ImmutableList.copyOf(ids);
}
}
acquire(Math.max(count - ids.size(), batchSize));
while (ids.size() < count) {
ids.add(counter++);
}
return ImmutableList.copyOf(ids);
} finally {
counterLock.unlock();
}
}
@VisibleForTesting
public void set(int val) throws OrmException {
// Don't bother spinning. This is only for tests, and a test that calls set
@@ -161,13 +188,13 @@ public class RepoSequence {
}
}
private void acquire() throws OrmException {
private void acquire(int count) throws OrmException {
try (Repository repo = repoManager.openRepository(projectName);
RevWalk rw = new RevWalk(repo)) {
TryAcquire attempt = new TryAcquire(repo, rw);
TryAcquire attempt = new TryAcquire(repo, rw, count);
checkResult(retryer.call(attempt));
counter = attempt.next;
limit = counter + batchSize;
limit = counter + count;
acquireCount++;
} catch (ExecutionException | RetryException e) {
Throwables.propagateIfInstanceOf(e.getCause(), OrmException.class);
@@ -186,12 +213,14 @@ public class RepoSequence {
private class TryAcquire implements Callable<RefUpdate.Result> {
private final Repository repo;
private final RevWalk rw;
private final int count;
private int next;
private TryAcquire(Repository repo, RevWalk rw) {
private TryAcquire(Repository repo, RevWalk rw, int count) {
this.repo = repo;
this.rw = rw;
this.count = count;
}
@Override
@@ -206,7 +235,7 @@ public class RepoSequence {
oldId = ref.getObjectId();
next = parse(oldId);
}
return store(repo, rw, oldId, next + batchSize);
return store(repo, rw, oldId, next + count);
}
private int parse(ObjectId id) throws IOException, OrmException {