Use local repo to get tree data if available. Fix some git2go memory leaks. Change-Id: If0f4bd865436f92f7e40dc482428ac812666f74e
diff --git a/cache/gitcache.go b/cache/gitcache.go index a24cba4..b79c9f1 100644 --- a/cache/gitcache.go +++ b/cache/gitcache.go
@@ -119,6 +119,20 @@ return runErr } +// OpenLocal returns an opened repository for the given URL, if it is available locally. +func (c *gitCache) OpenLocal(url string) *git.Repository { + p, err := c.gitPath(url) + if err != nil { + return nil + } + + repo, err := git.OpenRepository(p) + if err != nil { + return nil + } + return repo +} + // Open returns an opened repository for the given URL. If necessary, // the repository is cloned. func (c *gitCache) Open(url string) (*git.Repository, error) {
diff --git a/cache/gitcache_test.go b/cache/gitcache_test.go index 6d74ca4..8d4a99f 100644 --- a/cache/gitcache_test.go +++ b/cache/gitcache_test.go
@@ -1,7 +1,22 @@ +// Copyright 2016 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package cache import ( "io/ioutil" + "os" "testing" "time" ) @@ -17,6 +32,7 @@ if err != nil { t.Fatalf("TempDir: %v", err) } + defer os.RemoveAll(dir) cache, err := newGitCache(dir) if err != nil { @@ -24,6 +40,9 @@ } url := "file://" + testRepo.dir + if r := cache.OpenLocal(url); r != nil { + t.Errorf("OpenLocal(%s) succeeded", url) + } lazy := newLazyRepo(url, cache) if r := lazy.Repository(); r != nil { @@ -44,4 +63,8 @@ if repo := lazy.Repository(); repo == nil { t.Errorf("lazyRepo still not loaded after %s.", dt) } + + if r := cache.OpenLocal(url); r == nil { + t.Errorf("OpenLocal(%s) failed", url) + } }
diff --git a/cache/treecache.go b/cache/treecache.go index 2ea5f8a..1435f13 100644 --- a/cache/treecache.go +++ b/cache/treecache.go
@@ -108,13 +108,15 @@ if err != nil { return nil, err } + defer obj.Free() - obj, err = obj.Peel(git.ObjectTree) + peeledObj, err := obj.Peel(git.ObjectTree) if err != nil { return nil, err } + defer peeledObj.Free() - asTree, err := obj.AsTree() + asTree, err := peeledObj.AsTree() if err != nil { return nil, err } @@ -123,10 +125,10 @@ tree.ID = obj.Id().String() odb, err := repo.Odb() - if err != nil { return nil, err } + defer odb.Free() cb := func(n string, e *git.TreeEntry) int { t := "" @@ -163,6 +165,7 @@ err = lookErr return -1 } + defer obj.Free() blob, blobErr := obj.AsBlob() if blobErr != nil {
diff --git a/fs/gitilesfs.go b/fs/gitilesfs.go index 616b9f7..f9d5d1e 100644 --- a/fs/gitilesfs.go +++ b/fs/gitilesfs.go
@@ -179,6 +179,9 @@ if clone && repo == nil { r.lazyRepo.Clone() } + if repo != nil { + defer repo.Free() + } var content []byte if repo != nil { @@ -187,6 +190,7 @@ log.Println("LookupBlob: %v", err) return nil, syscall.ESPIPE } + defer blob.Free() content = blob.Contents() } else { path := r.shaMap[id]
diff --git a/fs/manifestfs.go b/fs/manifestfs.go index a6c8898..7eae4b0 100644 --- a/fs/manifestfs.go +++ b/fs/manifestfs.go
@@ -70,7 +70,7 @@ } } - root.trees, err = fetchTreeMap(cache.Tree, service, opts.Manifest) + root.trees, err = fetchTreeMap(cache, service, opts.Manifest) if err != nil { return nil, err } @@ -201,17 +201,13 @@ return nil } -func fetchTreeMap(treeCache *cache.TreeCache, service *gitiles.Service, mf *manifest.Manifest) (map[string]*gitiles.Tree, error) { +func fetchTreeMap(c *cache.Cache, service *gitiles.Service, mf *manifest.Manifest) (map[string]*gitiles.Tree, error) { type resultT struct { path string resp *gitiles.Tree err error } - // TODO(hanwen): if we have the repository, and commit - // locally, we should use cache.GetTree() instead of putting - // load on the remote Gitiles. - // Fetch all the trees in parallel. out := make(chan resultT, len(mf.Project)) for _, p := range mf.Project { @@ -222,13 +218,20 @@ return } - tree, err := treeCache.Get(revID) + tree, err := c.Tree.Get(revID) + if err != nil { + if repo := c.Git.OpenLocal(p.CloneURL); repo != nil { + defer repo.Free() + tree, err = cache.GetTree(repo, revID) + } + } + if err != nil { repoService := service.NewRepoService(p.Name) tree, err = repoService.GetTree(p.Revision, "", true) if err == nil { - if err := treeCache.Add(revID, tree); err != nil { + if err := c.Tree.Add(revID, tree); err != nil { log.Printf("treeCache.Add: %v", err) } }