aboutsummaryrefslogtreecommitdiffstats
path: root/storage/filesystem/object.go
diff options
context:
space:
mode:
authorJeremy Stribling <strib@alum.mit.edu>2018-10-11 16:24:25 -0700
committerJeremy Stribling <strib@alum.mit.edu>2018-10-11 17:12:21 -0700
commit1e1315d5e587d481e73e295dd18e50026af48c79 (patch)
tree5819d378bc667a0f39d51abc230fc678828d5234 /storage/filesystem/object.go
parent0bfe038a16551ede1d22bfb54f52c31b646a9e1a (diff)
downloadgo-git-1e1315d5e587d481e73e295dd18e50026af48c79.tar.gz
object: get object size without reading whole object
Signed-off-by: Jeremy Stribling <strib@alum.mit.edu>
Diffstat (limited to 'storage/filesystem/object.go')
-rw-r--r--storage/filesystem/object.go75
1 files changed, 75 insertions, 0 deletions
diff --git a/storage/filesystem/object.go b/storage/filesystem/object.go
index 68bd140..d2ba411 100644
--- a/storage/filesystem/object.go
+++ b/storage/filesystem/object.go
@@ -160,6 +160,81 @@ func (s *ObjectStorage) HasEncodedObject(h plumbing.Hash) (err error) {
return nil
}
+func (s *ObjectStorage) encodedObjectSizeFromUnpacked(h plumbing.Hash) (
+ size int64, err error) {
+ f, err := s.dir.Object(h)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return 0, plumbing.ErrObjectNotFound
+ }
+
+ return 0, err
+ }
+
+ r, err := objfile.NewReader(f)
+ if err != nil {
+ return 0, err
+ }
+ defer ioutil.CheckClose(r, &err)
+
+ _, size, err = r.Header()
+ return size, err
+}
+
+func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) (
+ size int64, err error) {
+ if err := s.requireIndex(); err != nil {
+ return 0, err
+ }
+
+ pack, _, offset := s.findObjectInPackfile(h)
+ if offset == -1 {
+ return 0, plumbing.ErrObjectNotFound
+ }
+
+ f, err := s.dir.ObjectPack(pack)
+ if err != nil {
+ return 0, err
+ }
+ defer ioutil.CheckClose(f, &err)
+
+ idx := s.index[pack]
+ hash, err := idx.FindHash(offset)
+ if err == nil {
+ obj, ok := s.deltaBaseCache.Get(hash)
+ if ok {
+ return obj.Size(), nil
+ }
+ }
+
+ if err != nil && err != plumbing.ErrObjectNotFound {
+ return 0, err
+ }
+
+ var p *packfile.Packfile
+ if s.deltaBaseCache != nil {
+ p = packfile.NewPackfileWithCache(idx, s.dir.Fs(), f, s.deltaBaseCache)
+ } else {
+ p = packfile.NewPackfile(idx, s.dir.Fs(), f)
+ }
+
+ return p.GetSizeByOffset(offset)
+}
+
+// EncodedObjectSize returns the plaintext size of the given object,
+// without actually reading the full object data from storage.
+func (s *ObjectStorage) EncodedObjectSize(h plumbing.Hash) (
+ size int64, err error) {
+ size, err = s.encodedObjectSizeFromUnpacked(h)
+ if err != nil && err != plumbing.ErrObjectNotFound {
+ return 0, err
+ } else if err == nil {
+ return size, nil
+ }
+
+ return s.encodedObjectSizeFromPackfile(h)
+}
+
// EncodedObject returns the object with the given hash, by searching for it in
// the packfile and the git object directories.
func (s *ObjectStorage) EncodedObject(t plumbing.ObjectType, h plumbing.Hash) (plumbing.EncodedObject, error) {