Browse Source

Expose the ObjectInserter that created an ObjectReader

We've found in Gerrit Code Review that it is common to pass around
both an ObjectReader (or more commonly a RevWalk wrapping one) and an
ObjectInserter. These code paths often assume that the ObjectReader
can read back any objects created by the ObjectInserter without
flushing. However, we previously had no way to enforce that constraint
programmatically, leading to hard-to-spot problems.

Provide a solution by exposing the ObjectInserter that created an
ObjectReader, when known. Callers can either continue passing both
objects and check:
  reader.getCreatedFromInserter() == inserter
or they can just pass around ObjectReader and extract the inserter
when it's needed (checking that it's not null at usage time).

Change-Id: Ibbf5d1968b506f6b47030ab1b046ffccb47352ea
tags/v4.4.0.201605041135-m1
Dave Borowitz 8 years ago
parent
commit
adff322a69

+ 5
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java View File

@@ -45,6 +45,7 @@ package org.eclipse.jgit.internal.storage.dfs;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;

import java.io.IOException;
@@ -97,6 +98,7 @@ public class DfsInserterTest {
assertEquals(0, db.getObjectDatabase().listPacks().size());

ObjectReader reader = ins.newReader();
assertSame(ins, reader.getCreatedFromInserter());
assertEquals("foo", readString(reader.open(id1)));
assertEquals("bar", readString(reader.open(id2)));
assertEquals(0, db.getObjectDatabase().listPacks().size());
@@ -118,6 +120,7 @@ public class DfsInserterTest {
assertEquals(0, db.getObjectDatabase().listPacks().size());

ObjectReader reader = ins.newReader();
assertSame(ins, reader.getCreatedFromInserter());
assertTrue(Arrays.equals(data, readStream(reader.open(id1))));
assertEquals(0, db.getObjectDatabase().listPacks().size());
ins.flush();
@@ -136,6 +139,7 @@ public class DfsInserterTest {
assertEquals(1, db.getObjectDatabase().listPacks().size());

ObjectReader reader = ins.newReader();
assertSame(ins, reader.getCreatedFromInserter());
assertEquals("foo", readString(reader.open(id1)));
assertEquals("bar", readString(reader.open(id2)));
assertEquals(1, db.getObjectDatabase().listPacks().size());
@@ -154,6 +158,7 @@ public class DfsInserterTest {
assertFalse(abbr1.equals(abbr2));

ObjectReader reader = ins.newReader();
assertSame(ins, reader.getCreatedFromInserter());
Collection<ObjectId> objs;
objs = reader.resolve(AbbreviatedObjectId.fromString(abbr1));
assertEquals(1, objs.size());

+ 5
- 0
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java View File

@@ -600,6 +600,11 @@ public class DfsInserter extends ObjectInserter {
return ctx.getShallowCommits();
}

@Override
public ObjectInserter getCreatedFromInserter() {
return DfsInserter.this;
}

@Override
public void close() {
ctx.close();

+ 1
- 1
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java View File

@@ -136,7 +136,7 @@ class ObjectDirectoryInserter extends ObjectInserter {

@Override
public ObjectReader newReader() {
return new WindowCursor(db);
return new WindowCursor(db, this);
}

@Override

+ 18
- 0
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java View File

@@ -53,6 +53,7 @@ import java.util.Set;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;

import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
@@ -69,6 +70,7 @@ import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.InflaterCache;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.ProgressMonitor;
@@ -84,10 +86,20 @@ final class WindowCursor extends ObjectReader implements ObjectReuseAsIs {

private DeltaBaseCache baseCache;

@Nullable
private final ObjectInserter createdFromInserter;

final FileObjectDatabase db;

WindowCursor(FileObjectDatabase db) {
this.db = db;
this.createdFromInserter = null;
}

WindowCursor(FileObjectDatabase db,
@Nullable ObjectDirectoryInserter createdFromInserter) {
this.db = db;
this.createdFromInserter = createdFromInserter;
}

DeltaBaseCache getDeltaBaseCache() {
@@ -329,6 +341,12 @@ final class WindowCursor extends ObjectReader implements ObjectReuseAsIs {
return WindowCache.getStreamFileThreshold();
}

@Override
@Nullable
public ObjectInserter getCreatedFromInserter() {
return createdFromInserter;
}

/** Release the current window cursor. */
@Override
public void close() {

+ 15
- 1
org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java View File

@@ -143,7 +143,18 @@ public abstract class ObjectInserter implements AutoCloseable {
}

public ObjectReader newReader() {
return delegate().newReader();
final ObjectReader dr = delegate().newReader();
return new ObjectReader.Filter() {
@Override
protected ObjectReader delegate() {
return dr;
}

@Override
public ObjectInserter getCreatedFromInserter() {
return ObjectInserter.Filter.this;
}
};
}

public void flush() throws IOException {
@@ -398,6 +409,9 @@ public abstract class ObjectInserter implements AutoCloseable {
* visible to the repository. The returned reader should only be used from
* the same thread as the inserter. Objects written by this inserter may not
* be visible to {@code this.newReader().newReader()}.
* <p>
* The returned reader should return this inserter instance from {@link
* ObjectReader#getCreatedFromInserter()}.
*
* @since 3.5
* @return reader for any object, including an object recently inserted by

+ 18
- 0
org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java View File

@@ -50,6 +50,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs;
@@ -421,6 +422,17 @@ public abstract class ObjectReader implements AutoCloseable {
return null;
}

/**
* @return the {@link ObjectInserter} from which this reader was created
* using {@code inserter.newReader()}, or null if this reader was not
* created from an inserter.
* @since 4.4
*/
@Nullable
public ObjectInserter getCreatedFromInserter() {
return null;
}

/**
* Release any resources used by this reader.
* <p>
@@ -524,6 +536,12 @@ public abstract class ObjectReader implements AutoCloseable {
return delegate().getBitmapIndex();
}

@Override
@Nullable
public ObjectInserter getCreatedFromInserter() {
return delegate().getCreatedFromInserter();
}

@Override
public void close() {
delegate().close();

Loading…
Cancel
Save