The reftable format supports fast inverse (SHA1 => ref) queries. If the ref database does not support fast inverse queries, it may be advantageous to build a complete SHA1 to ref map in advance for multiple uses. To let applications decide, this function indicates whether the inverse map is available. Signed-off-by: Han-Wen Nienhuys <hanwen@google.com> Change-Id: Idaf7e01075906972ec21332cade285289619c2b3tags/v5.6.0.201912101111-r
assertFalse(b.isSymbolic()); | assertFalse(b.isSymbolic()); | ||||
assertTrue(b.isPeeled()); | assertTrue(b.isPeeled()); | ||||
assertEquals(bCommit, b.getObjectId().name()); | assertEquals(bCommit, b.getObjectId().name()); | ||||
assertTrue(db.getRefDatabase().hasFastTipsWithSha1()); | |||||
} | } | ||||
@Test | @Test | ||||
assertFalse(b.isSymbolic()); | assertFalse(b.isSymbolic()); | ||||
assertTrue(b.isPeeled()); | assertTrue(b.isPeeled()); | ||||
assertEquals(bCommit, b.getObjectId().name()); | assertEquals(bCommit, b.getObjectId().name()); | ||||
assertFalse(db.getRefDatabase().hasFastTipsWithSha1()); | |||||
} | } | ||||
@Test | @Test |
assertEquals(expBytes, table.length); | assertEquals(expBytes, table.length); | ||||
} | } | ||||
@Test | |||||
public void hasObjMapRefs() throws IOException { | |||||
ArrayList<Ref> refs = new ArrayList<>(); | |||||
refs.add(ref(MASTER, 1)); | |||||
byte[] table = write(refs); | |||||
ReftableReader t = read(table); | |||||
assertTrue(t.hasObjectMap()); | |||||
} | |||||
@Test | |||||
public void hasObjMapRefsSmallTable() throws IOException { | |||||
ArrayList<Ref> refs = new ArrayList<>(); | |||||
ReftableConfig cfg = new ReftableConfig(); | |||||
cfg.setIndexObjects(false); | |||||
refs.add(ref(MASTER, 1)); | |||||
byte[] table = write(refs); | |||||
ReftableReader t = read(table); | |||||
assertTrue(t.hasObjectMap()); | |||||
} | |||||
@Test | |||||
public void hasObjLogs() throws IOException { | |||||
PersonIdent who = new PersonIdent("Log", "Ger", 1500079709, -8 * 60); | |||||
String msg = "test"; | |||||
ReftableConfig cfg = new ReftableConfig(); | |||||
cfg.setIndexObjects(false); | |||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); | |||||
ReftableWriter writer = new ReftableWriter(buffer) | |||||
.setMinUpdateIndex(1) | |||||
.setConfig(cfg) | |||||
.setMaxUpdateIndex(1) | |||||
.begin(); | |||||
writer.writeLog("master", 1, who, ObjectId.zeroId(), id(1), msg); | |||||
writer.finish(); | |||||
byte[] table = buffer.toByteArray(); | |||||
ReftableReader t = read(table); | |||||
assertTrue(t.hasObjectMap()); | |||||
} | |||||
@Test | |||||
public void hasObjMapRefsNoIndexObjects() throws IOException { | |||||
ArrayList<Ref> refs = new ArrayList<>(); | |||||
ReftableConfig cfg = new ReftableConfig(); | |||||
cfg.setIndexObjects(false); | |||||
cfg.setRefBlockSize(256); | |||||
cfg.setAlignBlocks(true); | |||||
// Fill up 5 blocks. | |||||
int N = 256 * 5 / 25; | |||||
for (int i= 0; i < N; i++) { | |||||
refs.add(ref(String.format("%02d/xxxxxxxxxx", i), i)); | |||||
} | |||||
byte[] table = write(refs, cfg); | |||||
ReftableReader t = read(table); | |||||
assertFalse(t.hasObjectMap()); | |||||
} | |||||
@Test | @Test | ||||
public void oneIdRef() throws IOException { | public void oneIdRef() throws IOException { | ||||
Ref exp = ref(MASTER, 1); | Ref exp = ref(MASTER, 1); | ||||
} | } | ||||
private byte[] write(Collection<Ref> refs) throws IOException { | private byte[] write(Collection<Ref> refs) throws IOException { | ||||
return write(refs, new ReftableConfig()); | |||||
} | |||||
private byte[] write(Collection<Ref> refs, ReftableConfig cfg) throws IOException { | |||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); | ByteArrayOutputStream buffer = new ByteArrayOutputStream(); | ||||
stats = new ReftableWriter(buffer) | stats = new ReftableWriter(buffer) | ||||
.setConfig(cfg) | |||||
.begin() | .begin() | ||||
.sortAndWriteRefs(refs) | .sortAndWriteRefs(refs) | ||||
.finish() | .finish() |
return reftableDatabase.getTipsWithSha1(id); | return reftableDatabase.getTipsWithSha1(id); | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
@Override | |||||
public boolean hasFastTipsWithSha1() throws IOException { | |||||
return reftableDatabase.hasFastTipsWithSha1(); | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | @Override | ||||
public Ref peel(Ref ref) throws IOException { | public Ref peel(Ref ref) throws IOException { |
&& new File(repoDir, Constants.REFTABLE).isDirectory(); | && new File(repoDir, Constants.REFTABLE).isDirectory(); | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
@Override | |||||
public boolean hasFastTipsWithSha1() throws IOException { | |||||
return reftableDatabase.hasFastTipsWithSha1(); | |||||
} | |||||
/** | /** | ||||
* Runs a full compaction for GC purposes. | * Runs a full compaction for GC purposes. | ||||
* @throws IOException on I/O errors | * @throws IOException on I/O errors |
: 0; | : 0; | ||||
} | } | ||||
/** {@inheritDoc} */ | |||||
@Override | |||||
public boolean hasObjectMap() throws IOException { | |||||
boolean has = true; | |||||
for (int i = 0; has && i < tables.length; i++) { | |||||
has = has && tables[i].hasObjectMap(); | |||||
}; | |||||
return has; | |||||
} | |||||
/** {@inheritDoc} */ | /** {@inheritDoc} */ | ||||
@Override | @Override | ||||
public RefCursor allRefs() throws IOException { | public RefCursor allRefs() throws IOException { |
*/ | */ | ||||
public abstract RefCursor byObjectId(AnyObjectId id) throws IOException; | public abstract RefCursor byObjectId(AnyObjectId id) throws IOException; | ||||
/** | |||||
* @return whether this reftable can do a fast SHA1 => ref lookup. | |||||
* @throws IOException on I/O problems. | |||||
*/ | |||||
public abstract boolean hasObjectMap() throws IOException; | |||||
/** | /** | ||||
* Seek reader to read log records. | * Seek reader to read log records. | ||||
* | * |
return Collections.unmodifiableList(all); | return Collections.unmodifiableList(all); | ||||
} | } | ||||
/** | |||||
* @return whether there is a fast SHA1 to ref map. | |||||
* @throws IOException in case of I/O problems. | |||||
*/ | |||||
public boolean hasFastTipsWithSha1() throws IOException { | |||||
lock.lock(); | |||||
try { | |||||
return reader().hasObjectMap(); | |||||
} finally { | |||||
lock.unlock(); | |||||
} | |||||
} | |||||
/** | /** | ||||
* Returns all refs that resolve directly to the given {@link ObjectId}. | * Returns all refs that resolve directly to the given {@link ObjectId}. | ||||
* Includes peeled {@linkObjectId}s. | * Includes peeled {@linkObjectId}s. |
return blockSize; | return blockSize; | ||||
} | } | ||||
@Override | |||||
public boolean hasObjectMap() throws IOException { | |||||
if (objIndexPosition == -1) { | |||||
readFileFooter(); | |||||
} | |||||
// We have the map, we have no refs, or the table is small. | |||||
return (objPosition > 0 || refEnd == 24 || refIndexPosition == 0); | |||||
} | |||||
/** | /** | ||||
* Get the minimum update index for log entries that appear in this | * Get the minimum update index for log entries that appear in this | ||||
* reftable. | * reftable. |
|| id.equals(r.getPeeledObjectId())).collect(toSet()); | || id.equals(r.getPeeledObjectId())).collect(toSet()); | ||||
} | } | ||||
/** | |||||
* If the ref database does not support fast inverse queries, it may | |||||
* be advantageous to build a complete SHA1 to ref map in advance for | |||||
* multiple uses. To let applications decide on this decision, | |||||
* this function indicates whether the inverse map is available. | |||||
* | |||||
* @return whether this RefDatabase supports fast inverse ref queries. | |||||
* @throws IOException on I/O problems. | |||||
* @since 5.6 | |||||
*/ | |||||
public boolean hasFastTipsWithSha1() throws IOException { | |||||
return false; | |||||
} | |||||
/** | /** | ||||
* Check if any refs exist in the ref database. | * Check if any refs exist in the ref database. | ||||
* <p> | * <p> |