@@ -26,6 +26,10 @@ type ObjectStorage struct {
26
26
27
27
dir * dotgit.DotGit
28
28
index map [plumbing.Hash ]idxfile.Index
29
+
30
+ packList []plumbing.Hash
31
+ packListIdx int
32
+ packfiles map [plumbing.Hash ]* packfile.Packfile
29
33
}
30
34
31
35
// NewObjectStorage creates a new ObjectStorage with the given .git directory and cache.
@@ -187,6 +191,57 @@ func (s *ObjectStorage) encodedObjectSizeFromUnpacked(h plumbing.Hash) (
187
191
return size , err
188
192
}
189
193
194
+ func (s * ObjectStorage ) packfile (idx idxfile.Index , pack plumbing.Hash ) (* packfile.Packfile , error ) {
195
+ if s .packfiles == nil {
196
+ if s .options .MaxOpenDescriptors > 0 {
197
+ s .packList = make ([]plumbing.Hash , s .options .MaxOpenDescriptors )
198
+ s .packfiles = make (map [plumbing.Hash ]* packfile.Packfile , s .options .MaxOpenDescriptors )
199
+ } else {
200
+ s .packfiles = make (map [plumbing.Hash ]* packfile.Packfile )
201
+ }
202
+ }
203
+
204
+ if p , ok := s .packfiles [pack ]; ok {
205
+ return p , nil
206
+ }
207
+
208
+ f , err := s .dir .ObjectPack (pack )
209
+ if err != nil {
210
+ return nil , err
211
+ }
212
+
213
+ var p * packfile.Packfile
214
+ if s .objectCache != nil {
215
+ p = packfile .NewPackfileWithCache (idx , s .dir .Fs (), f , s .objectCache )
216
+ } else {
217
+ p = packfile .NewPackfile (idx , s .dir .Fs (), f )
218
+ }
219
+
220
+ if s .options .KeepDescriptors {
221
+ s .packfiles [pack ] = p
222
+ } else if s .options .MaxOpenDescriptors > 0 {
223
+ if next := s .packList [s .packListIdx ]; ! next .IsZero () {
224
+ open := s .packfiles [next ]
225
+ delete (s .packfiles , next )
226
+ if open != nil {
227
+ if err = open .Close (); err != nil {
228
+ return nil , err
229
+ }
230
+ }
231
+ }
232
+
233
+ s .packList [s .packListIdx ] = pack
234
+ s .packfiles [pack ] = p
235
+
236
+ s .packListIdx ++
237
+ if s .packListIdx >= len (s .packList ) {
238
+ s .packListIdx = 0
239
+ }
240
+ }
241
+
242
+ return p , err
243
+ }
244
+
190
245
func (s * ObjectStorage ) encodedObjectSizeFromPackfile (h plumbing.Hash ) (
191
246
size int64 , err error ) {
192
247
if err := s .requireIndex (); err != nil {
@@ -198,12 +253,6 @@ func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) (
198
253
return 0 , plumbing .ErrObjectNotFound
199
254
}
200
255
201
- f , err := s .dir .ObjectPack (pack )
202
- if err != nil {
203
- return 0 , err
204
- }
205
- defer ioutil .CheckClose (f , & err )
206
-
207
256
idx := s .index [pack ]
208
257
hash , err := idx .FindHash (offset )
209
258
if err == nil {
@@ -215,11 +264,13 @@ func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) (
215
264
return 0 , err
216
265
}
217
266
218
- var p * packfile.Packfile
219
- if s .objectCache != nil {
220
- p = packfile .NewPackfileWithCache (idx , s .dir .Fs (), f , s .objectCache )
221
- } else {
222
- p = packfile .NewPackfile (idx , s .dir .Fs (), f )
267
+ p , err := s .packfile (idx , pack )
268
+ if err != nil {
269
+ return 0 , err
270
+ }
271
+
272
+ if ! s .options .KeepDescriptors && s .options .MaxOpenDescriptors == 0 {
273
+ defer ioutil .CheckClose (p , & err )
223
274
}
224
275
225
276
return p .GetSizeByOffset (offset )
@@ -361,29 +412,28 @@ func (s *ObjectStorage) getFromPackfile(h plumbing.Hash, canBeDelta bool) (
361
412
return nil , plumbing .ErrObjectNotFound
362
413
}
363
414
364
- f , err := s .dir .ObjectPack (pack )
415
+ idx := s .index [pack ]
416
+ p , err := s .packfile (idx , pack )
365
417
if err != nil {
366
418
return nil , err
367
419
}
368
420
369
- if ! s .options .KeepDescriptors {
370
- defer ioutil .CheckClose (f , & err )
421
+ if ! s .options .KeepDescriptors && s . options . MaxOpenDescriptors == 0 {
422
+ defer ioutil .CheckClose (p , & err )
371
423
}
372
424
373
- idx := s .index [pack ]
374
425
if canBeDelta {
375
- return s .decodeDeltaObjectAt (f , idx , offset , hash )
426
+ return s .decodeDeltaObjectAt (p , offset , hash )
376
427
}
377
428
378
- return s .decodeObjectAt (f , idx , offset )
429
+ return s .decodeObjectAt (p , offset )
379
430
}
380
431
381
432
func (s * ObjectStorage ) decodeObjectAt (
382
- f billy.File ,
383
- idx idxfile.Index ,
433
+ p * packfile.Packfile ,
384
434
offset int64 ,
385
435
) (plumbing.EncodedObject , error ) {
386
- hash , err := idx .FindHash (offset )
436
+ hash , err := p .FindHash (offset )
387
437
if err == nil {
388
438
obj , ok := s .objectCache .Get (hash )
389
439
if ok {
@@ -395,28 +445,16 @@ func (s *ObjectStorage) decodeObjectAt(
395
445
return nil , err
396
446
}
397
447
398
- var p * packfile.Packfile
399
- if s .objectCache != nil {
400
- p = packfile .NewPackfileWithCache (idx , s .dir .Fs (), f , s .objectCache )
401
- } else {
402
- p = packfile .NewPackfile (idx , s .dir .Fs (), f )
403
- }
404
-
405
448
return p .GetByOffset (offset )
406
449
}
407
450
408
451
func (s * ObjectStorage ) decodeDeltaObjectAt (
409
- f billy.File ,
410
- idx idxfile.Index ,
452
+ p * packfile.Packfile ,
411
453
offset int64 ,
412
454
hash plumbing.Hash ,
413
455
) (plumbing.EncodedObject , error ) {
414
- if _ , err := f .Seek (0 , io .SeekStart ); err != nil {
415
- return nil , err
416
- }
417
-
418
- p := packfile .NewScanner (f )
419
- header , err := p .SeekObjectHeader (offset )
456
+ scan := p .Scanner ()
457
+ header , err := scan .SeekObjectHeader (offset )
420
458
if err != nil {
421
459
return nil , err
422
460
}
@@ -429,12 +467,12 @@ func (s *ObjectStorage) decodeDeltaObjectAt(
429
467
case plumbing .REFDeltaObject :
430
468
base = header .Reference
431
469
case plumbing .OFSDeltaObject :
432
- base , err = idx .FindHash (header .OffsetReference )
470
+ base , err = p .FindHash (header .OffsetReference )
433
471
if err != nil {
434
472
return nil , err
435
473
}
436
474
default :
437
- return s .decodeObjectAt (f , idx , offset )
475
+ return s .decodeObjectAt (p , offset )
438
476
}
439
477
440
478
obj := & plumbing.MemoryObject {}
@@ -444,7 +482,7 @@ func (s *ObjectStorage) decodeDeltaObjectAt(
444
482
return nil , err
445
483
}
446
484
447
- if _ , _ , err := p .NextObject (w ); err != nil {
485
+ if _ , _ , err := scan .NextObject (w ); err != nil {
448
486
return nil , err
449
487
}
450
488
@@ -515,7 +553,20 @@ func (s *ObjectStorage) buildPackfileIters(
515
553
516
554
// Close closes all opened files.
517
555
func (s * ObjectStorage ) Close () error {
518
- return s .dir .Close ()
556
+ var firstError error
557
+ if s .options .KeepDescriptors || s .options .MaxOpenDescriptors > 0 {
558
+ for _ , packfile := range s .packfiles {
559
+ err := packfile .Close ()
560
+ if firstError == nil && err != nil {
561
+ firstError = err
562
+ }
563
+ }
564
+ }
565
+
566
+ s .packfiles = nil
567
+ s .dir .Close ()
568
+
569
+ return firstError
519
570
}
520
571
521
572
type lazyPackfilesIter struct {
0 commit comments