Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit f2fd929

Browse files
committed
feat: avoid memory allocation on resolveDeltas
Signed-off-by: Nao YONASHIRO <owan.orisano@gmail.com>
1 parent 509b128 commit f2fd929

File tree

1 file changed

+53
-46
lines changed

1 file changed

+53
-46
lines changed

plumbing/format/packfile/parser.go

Lines changed: 53 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"errors"
66
"io"
7+
"io/ioutil"
78

89
"gopkg.in/src-d/go-git.v4/plumbing"
910
"gopkg.in/src-d/go-git.v4/plumbing/cache"
@@ -263,11 +264,14 @@ func (p *Parser) indexObjects() error {
263264
}
264265

265266
func (p *Parser) resolveDeltas() error {
267+
buf := &bytes.Buffer{}
266268
for _, obj := range p.oi {
267-
content, err := p.get(obj)
269+
buf.Reset()
270+
err := p.get(obj, buf)
268271
if err != nil {
269272
return err
270273
}
274+
content := buf.Bytes()
271275

272276
if err := p.onInflatedObjectHeader(obj.Type, obj.Length, obj.Offset); err != nil {
273277
return err
@@ -279,7 +283,7 @@ func (p *Parser) resolveDeltas() error {
279283

280284
if !obj.IsDelta() && len(obj.Children) > 0 {
281285
for _, child := range obj.Children {
282-
if _, err := p.resolveObject(child, content); err != nil {
286+
if err := p.resolveObject(ioutil.Discard, child, content); err != nil {
283287
return err
284288
}
285289
}
@@ -294,120 +298,123 @@ func (p *Parser) resolveDeltas() error {
294298
return nil
295299
}
296300

297-
func (p *Parser) get(o *objectInfo) (b []byte, err error) {
298-
var ok bool
301+
func (p *Parser) get(o *objectInfo, buf *bytes.Buffer) error {
299302
if !o.ExternalRef { // skip cache check for placeholder parents
300-
b, ok = p.cache.Get(o.Offset)
303+
b, ok := p.cache.Get(o.Offset)
304+
if ok {
305+
_, err := buf.Write(b)
306+
return err
307+
}
301308
}
302309

303310
// If it's not on the cache and is not a delta we can try to find it in the
304311
// storage, if there's one. External refs must enter here.
305-
if !ok && p.storage != nil && !o.Type.IsDelta() {
312+
if p.storage != nil && !o.Type.IsDelta() {
306313
e, err := p.storage.EncodedObject(plumbing.AnyObject, o.SHA1)
307314
if err != nil {
308-
return nil, err
315+
return err
309316
}
310317
o.Type = e.Type()
311318

312319
r, err := e.Reader()
313320
if err != nil {
314-
return nil, err
315-
}
316-
317-
b = make([]byte, e.Size())
318-
if _, err = r.Read(b); err != nil {
319-
return nil, err
321+
return err
320322
}
321-
}
322323

323-
if b != nil {
324-
return b, nil
324+
_, err = buf.ReadFrom(io.LimitReader(r, e.Size()))
325+
return err
325326
}
326327

327328
if o.ExternalRef {
328329
// we were not able to resolve a ref in a thin pack
329-
return nil, ErrReferenceDeltaNotFound
330+
return ErrReferenceDeltaNotFound
330331
}
331332

332-
var data []byte
333333
if o.DiskType.IsDelta() {
334-
base, err := p.get(o.Parent)
334+
b := bufPool.Get().(*bytes.Buffer)
335+
defer bufPool.Put(b)
336+
b.Reset()
337+
err := p.get(o.Parent, b)
335338
if err != nil {
336-
return nil, err
339+
return err
337340
}
341+
base := b.Bytes()
338342

339-
data, err = p.resolveObject(o, base)
343+
err = p.resolveObject(buf, o, base)
340344
if err != nil {
341-
return nil, err
345+
return err
342346
}
343347
} else {
344-
data, err = p.readData(o)
348+
err := p.readData(buf, o)
345349
if err != nil {
346-
return nil, err
350+
return err
347351
}
348352
}
349353

350354
if len(o.Children) > 0 {
355+
data := make([]byte, buf.Len())
356+
copy(data, buf.Bytes())
351357
p.cache.Put(o.Offset, data)
352358
}
353-
354-
return data, nil
359+
return nil
355360
}
356361

357362
func (p *Parser) resolveObject(
363+
w io.Writer,
358364
o *objectInfo,
359365
base []byte,
360-
) ([]byte, error) {
366+
) error {
361367
if !o.DiskType.IsDelta() {
362-
return nil, nil
368+
return nil
363369
}
364-
365-
data, err := p.readData(o)
370+
buf := bufPool.Get().(*bytes.Buffer)
371+
defer bufPool.Put(buf)
372+
buf.Reset()
373+
err := p.readData(buf, o)
366374
if err != nil {
367-
return nil, err
375+
return err
368376
}
377+
data := buf.Bytes()
369378

370379
data, err = applyPatchBase(o, data, base)
371380
if err != nil {
372-
return nil, err
381+
return err
373382
}
374383

375384
if p.storage != nil {
376385
obj := new(plumbing.MemoryObject)
377386
obj.SetSize(o.Size())
378387
obj.SetType(o.Type)
379388
if _, err := obj.Write(data); err != nil {
380-
return nil, err
389+
return err
381390
}
382391

383392
if _, err := p.storage.SetEncodedObject(obj); err != nil {
384-
return nil, err
393+
return err
385394
}
386395
}
387-
388-
return data, nil
396+
_, err = w.Write(data)
397+
return err
389398
}
390399

391-
func (p *Parser) readData(o *objectInfo) ([]byte, error) {
400+
func (p *Parser) readData(w io.Writer, o *objectInfo) error {
392401
if !p.scanner.IsSeekable && o.DiskType.IsDelta() {
393402
data, ok := p.deltas[o.Offset]
394403
if !ok {
395-
return nil, ErrDeltaNotCached
404+
return ErrDeltaNotCached
396405
}
397-
398-
return data, nil
406+
_, err := w.Write(data)
407+
return err
399408
}
400409

401410
if _, err := p.scanner.SeekObjectHeader(o.Offset); err != nil {
402-
return nil, err
411+
return err
403412
}
404413

405-
buf := new(bytes.Buffer)
406-
if _, _, err := p.scanner.NextObject(buf); err != nil {
407-
return nil, err
414+
if _, _, err := p.scanner.NextObject(w); err != nil {
415+
return err
408416
}
409-
410-
return buf.Bytes(), nil
417+
return nil
411418
}
412419

413420
func applyPatchBase(ota *objectInfo, data, base []byte) ([]byte, error) {

0 commit comments

Comments
 (0)