Merge pull request #720 from jfontan/improvement/cache-delete-more-than-one-object

plumbing: cache, modify cache to delete more than one item to free space
diff --git a/plumbing/cache/object_lru.go b/plumbing/cache/object_lru.go
index d99a5c9..0494539 100644
--- a/plumbing/cache/object_lru.go
+++ b/plumbing/cache/object_lru.go
@@ -51,11 +51,11 @@
 
 	objSize := FileSize(obj.Size())
 
-	if objSize >= c.MaxSize {
+	if objSize > c.MaxSize {
 		return
 	}
 
-	if c.actualSize+objSize > c.MaxSize {
+	for c.actualSize+objSize > c.MaxSize {
 		last := c.ll.Back()
 		lastObj := last.Value.(plumbing.EncodedObject)
 		lastSize := FileSize(lastObj.Size())
@@ -63,10 +63,6 @@
 		c.ll.Remove(last)
 		delete(c.cache, lastObj.Hash())
 		c.actualSize -= lastSize
-
-		if c.actualSize+objSize > c.MaxSize {
-			return
-		}
 	}
 
 	ee := c.ll.PushFront(obj)
diff --git a/plumbing/cache/object_test.go b/plumbing/cache/object_test.go
index ec01d60..ac3f0a3 100644
--- a/plumbing/cache/object_test.go
+++ b/plumbing/cache/object_test.go
@@ -19,6 +19,7 @@
 	bObject plumbing.EncodedObject
 	cObject plumbing.EncodedObject
 	dObject plumbing.EncodedObject
+	eObject plumbing.EncodedObject
 }
 
 var _ = Suite(&ObjectSuite{})
@@ -28,6 +29,7 @@
 	s.bObject = newObject("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 3*Byte)
 	s.cObject = newObject("cccccccccccccccccccccccccccccccccccccccc", 1*Byte)
 	s.dObject = newObject("dddddddddddddddddddddddddddddddddddddddd", 1*Byte)
+	s.eObject = newObject("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", 2*Byte)
 
 	s.c = make(map[string]Object)
 	s.c["two_bytes"] = NewObjectLRU(2 * Byte)
@@ -70,6 +72,24 @@
 	c.Assert(obj, NotNil)
 }
 
+func (s *ObjectSuite) TestEvictMultipleObjects(c *C) {
+	o := s.c["two_bytes"]
+
+	o.Put(s.cObject)
+	o.Put(s.dObject) // now cache is full with two objects
+	o.Put(s.eObject) // this put should evict all previous objects
+
+	obj, ok := o.Get(s.cObject.Hash())
+	c.Assert(ok, Equals, false)
+	c.Assert(obj, IsNil)
+	obj, ok = o.Get(s.dObject.Hash())
+	c.Assert(ok, Equals, false)
+	c.Assert(obj, IsNil)
+	obj, ok = o.Get(s.eObject.Hash())
+	c.Assert(ok, Equals, true)
+	c.Assert(obj, NotNil)
+}
+
 func (s *ObjectSuite) TestClear(c *C) {
 	for _, o := range s.c {
 		o.Put(s.aObject)
diff --git a/plumbing/format/packfile/decoder.go b/plumbing/format/packfile/decoder.go
index cb78701..f706e5d 100644
--- a/plumbing/format/packfile/decoder.go
+++ b/plumbing/format/packfile/decoder.go
@@ -407,6 +407,8 @@
 		if err != nil {
 			return 0, err
 		}
+
+		d.cachePut(base)
 	}
 
 	obj.SetType(base.Type())