Просмотр исходного кода

tree:<depth> should not traverse overly-deep trees

If we are traversing a tree which is too deep, then there is no need to
traverse the children. Skipping children is much faster than traversing
the possibly thousands of objects which are directly or indirectly
referenced by the tree.

Change-Id: I6d68cc1d35da48e3288b9cc80356a281ab36863d
Signed-off-by: Matthew DeVore <matvore@gmail.com>
tags/v5.4.0.201905081430-m2
Matthew DeVore 5 лет назад
Родитель
Сommit
175e66548b

+ 7
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java Просмотреть файл

import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTag; import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.storage.pack.PackStatistics;
import org.eclipse.jgit.transport.UploadPack.RequestPolicy; import org.eclipse.jgit.transport.UploadPack.RequestPolicy;
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;


private TestRepository<InMemoryRepository> remote; private TestRepository<InMemoryRepository> remote;


private PackStatistics stats;

@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
server = newRepo("server"); server = newRepo("server");


ByteArrayOutputStream recv = new ByteArrayOutputStream(); ByteArrayOutputStream recv = new ByteArrayOutputStream();
up.upload(send, recv, null); up.upload(send, recv, null);
stats = up.getStatistics();


return new ByteArrayInputStream(recv.toByteArray()); return new ByteArrayInputStream(recv.toByteArray());
} }
.has(preparator.blobLowDepth.toObjectId())); .has(preparator.blobLowDepth.toObjectId()));
assertFalse(client.getObjectDatabase() assertFalse(client.getObjectDatabase()
.has(preparator.blobHighDepth.toObjectId())); .has(preparator.blobHighDepth.toObjectId()));
assertEquals(1, stats.getTreesTraversed());
} }


@Test @Test
.has(preparator.blobLowDepth.toObjectId())); .has(preparator.blobLowDepth.toObjectId()));
assertFalse(client.getObjectDatabase() assertFalse(client.getObjectDatabase()
.has(preparator.blobHighDepth.toObjectId())); .has(preparator.blobHighDepth.toObjectId()));
assertEquals(1, stats.getTreesTraversed());
} }


@Test @Test
.has(preparator.blobLowDepth.toObjectId())); .has(preparator.blobLowDepth.toObjectId()));
assertFalse(client.getObjectDatabase() assertFalse(client.getObjectDatabase()
.has(preparator.blobHighDepth.toObjectId())); .has(preparator.blobHighDepth.toObjectId()));
assertEquals(2, stats.getTreesTraversed());
} }


/** /**

+ 15
- 4
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java Просмотреть файл

/** /**
* Determines if the object should be omitted from the pack as a result of * Determines if the object should be omitted from the pack as a result of
* its depth (probably because of the tree:<depth> filter). * its depth (probably because of the tree:<depth> filter).
* <p>
* Causes {@code walker} to skip traversing the current tree, which ought to
* have just started traversal, assuming this method is called as soon as a
* new depth is reached.
* <p>
* This method increments the {@code treesTraversed} statistic.
* *
* @param obj * @param obj
* the object to check whether it should be omitted. * the object to check whether it should be omitted.
// A blob is considered one level deeper than the tree that contains it. // A blob is considered one level deeper than the tree that contains it.
if (obj.getType() == OBJ_BLOB) { if (obj.getType() == OBJ_BLOB) {
treeDepth++; treeDepth++;
} else {
stats.treesTraversed++;
} }


// TODO: Do not continue traversing the tree, since its children
// will also be too deep.
return filterSpec.getTreeDepthLimit() != -1 &&
treeDepth > filterSpec.getTreeDepthLimit();
if (filterSpec.getTreeDepthLimit() < 0 ||
treeDepth <= filterSpec.getTreeDepthLimit()) {
return false;
}

walker.skipTree();
return true;
} }


// Adds the given object as an object to be packed, first performing // Adds the given object as an object to be packed, first performing

+ 11
- 0
org.eclipse.jgit/src/org/eclipse/jgit/revwalk/ObjectWalk.java Просмотреть файл

} }
} }


/**
* Skips the current tree such that {@link #nextObject()} does not return
* any objects inside it. This should be called right after
* {@link #nextObject()} returns the tree.
*
* @since 5.4
*/
public void skipTree() {
currVisit.ptr = currVisit.buf.length;
}

/** /**
* Pop the next most recent object. * Pop the next most recent object.
* *

+ 11
- 0
org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackStatistics.java Просмотреть файл

/** Time in ms spent writing the pack. */ /** Time in ms spent writing the pack. */
public long timeWriting; public long timeWriting;


/** Number of trees traversed in the walk when writing the pack. */
public long treesTraversed;

/** /**
* Statistics about each object type in the pack (commits, tags, trees * Statistics about each object type in the pack (commits, tags, trees
* and blobs.) * and blobs.)
return statistics.timeWriting; return statistics.timeWriting;
} }


/**
* @return number of trees traversed in the walk when writing the pack.
* @since 5.4
*/
public long getTreesTraversed() {
return statistics.treesTraversed;
}

/** /**
* Get total time spent processing this pack. * Get total time spent processing this pack.
* *

Загрузка…
Отмена
Сохранить