@@ -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,73 @@ 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 p := s .packfileFromCache (pack ); p != nil {
196
+ return p , nil
197
+ }
198
+
199
+ f , err := s .dir .ObjectPack (pack )
200
+ if err != nil {
201
+ return nil , err
202
+ }
203
+
204
+ var p * packfile.Packfile
205
+ if s .objectCache != nil {
206
+ p = packfile .NewPackfileWithCache (idx , s .dir .Fs (), f , s .objectCache )
207
+ } else {
208
+ p = packfile .NewPackfile (idx , s .dir .Fs (), f )
209
+ }
210
+
211
+ return p , s .storePackfileInCache (pack , p )
212
+ }
213
+
214
+ func (s * ObjectStorage ) packfileFromCache (hash plumbing.Hash ) * packfile.Packfile {
215
+ if s .packfiles == nil {
216
+ if s .options .KeepDescriptors {
217
+ s .packfiles = make (map [plumbing.Hash ]* packfile.Packfile )
218
+ } else if s .options .MaxOpenDescriptors > 0 {
219
+ s .packList = make ([]plumbing.Hash , s .options .MaxOpenDescriptors )
220
+ s .packfiles = make (map [plumbing.Hash ]* packfile.Packfile , s .options .MaxOpenDescriptors )
221
+ }
222
+ }
223
+
224
+ return s .packfiles [hash ]
225
+ }
226
+
227
+ func (s * ObjectStorage ) storePackfileInCache (hash plumbing.Hash , p * packfile.Packfile ) error {
228
+ if s .options .KeepDescriptors {
229
+ s .packfiles [hash ] = p
230
+ return nil
231
+ }
232
+
233
+ if s .options .MaxOpenDescriptors <= 0 {
234
+ return nil
235
+ }
236
+
237
+ // start over as the limit of packList is hit
238
+ if s .packListIdx >= len (s .packList ) {
239
+ s .packListIdx = 0
240
+ }
241
+
242
+ // close the existing packfile if open
243
+ if next := s .packList [s .packListIdx ]; ! next .IsZero () {
244
+ open := s .packfiles [next ]
245
+ delete (s .packfiles , next )
246
+ if open != nil {
247
+ if err := open .Close (); err != nil {
248
+ return err
249
+ }
250
+ }
251
+ }
252
+
253
+ // cache newly open packfile
254
+ s .packList [s .packListIdx ] = hash
255
+ s .packfiles [hash ] = p
256
+ s .packListIdx ++
257
+
258
+ return nil
259
+ }
260
+
190
261
func (s * ObjectStorage ) encodedObjectSizeFromPackfile (h plumbing.Hash ) (
191
262
size int64 , err error ) {
192
263
if err := s .requireIndex (); err != nil {
@@ -198,12 +269,6 @@ func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) (
198
269
return 0 , plumbing .ErrObjectNotFound
199
270
}
200
271
201
- f , err := s .dir .ObjectPack (pack )
202
- if err != nil {
203
- return 0 , err
204
- }
205
- defer ioutil .CheckClose (f , & err )
206
-
207
272
idx := s .index [pack ]
208
273
hash , err := idx .FindHash (offset )
209
274
if err == nil {
@@ -215,11 +280,13 @@ func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) (
215
280
return 0 , err
216
281
}
217
282
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 )
283
+ p , err := s .packfile (idx , pack )
284
+ if err != nil {
285
+ return 0 , err
286
+ }
287
+
288
+ if ! s .options .KeepDescriptors && s .options .MaxOpenDescriptors == 0 {
289
+ defer ioutil .CheckClose (p , & err )
223
290
}
224
291
225
292
return p .GetSizeByOffset (offset )
@@ -361,29 +428,28 @@ func (s *ObjectStorage) getFromPackfile(h plumbing.Hash, canBeDelta bool) (
361
428
return nil , plumbing .ErrObjectNotFound
362
429
}
363
430
364
- f , err := s .dir .ObjectPack (pack )
431
+ idx := s .index [pack ]
432
+ p , err := s .packfile (idx , pack )
365
433
if err != nil {
366
434
return nil , err
367
435
}
368
436
369
- if ! s .options .KeepDescriptors {
370
- defer ioutil .CheckClose (f , & err )
437
+ if ! s .options .KeepDescriptors && s . options . MaxOpenDescriptors == 0 {
438
+ defer ioutil .CheckClose (p , & err )
371
439
}
372
440
373
- idx := s .index [pack ]
374
441
if canBeDelta {
375
- return s .decodeDeltaObjectAt (f , idx , offset , hash )
442
+ return s .decodeDeltaObjectAt (p , offset , hash )
376
443
}
377
444
378
- return s .decodeObjectAt (f , idx , offset )
445
+ return s .decodeObjectAt (p , offset )
379
446
}
380
447
381
448
func (s * ObjectStorage ) decodeObjectAt (
382
- f billy.File ,
383
- idx idxfile.Index ,
449
+ p * packfile.Packfile ,
384
450
offset int64 ,
385
451
) (plumbing.EncodedObject , error ) {
386
- hash , err := idx .FindHash (offset )
452
+ hash , err := p .FindHash (offset )
387
453
if err == nil {
388
454
obj , ok := s .objectCache .Get (hash )
389
455
if ok {
@@ -395,28 +461,16 @@ func (s *ObjectStorage) decodeObjectAt(
395
461
return nil , err
396
462
}
397
463
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
464
return p .GetByOffset (offset )
406
465
}
407
466
408
467
func (s * ObjectStorage ) decodeDeltaObjectAt (
409
- f billy.File ,
410
- idx idxfile.Index ,
468
+ p * packfile.Packfile ,
411
469
offset int64 ,
412
470
hash plumbing.Hash ,
413
471
) (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 )
472
+ scan := p .Scanner ()
473
+ header , err := scan .SeekObjectHeader (offset )
420
474
if err != nil {
421
475
return nil , err
422
476
}
@@ -429,12 +483,12 @@ func (s *ObjectStorage) decodeDeltaObjectAt(
429
483
case plumbing .REFDeltaObject :
430
484
base = header .Reference
431
485
case plumbing .OFSDeltaObject :
432
- base , err = idx .FindHash (header .OffsetReference )
486
+ base , err = p .FindHash (header .OffsetReference )
433
487
if err != nil {
434
488
return nil , err
435
489
}
436
490
default :
437
- return s .decodeObjectAt (f , idx , offset )
491
+ return s .decodeObjectAt (p , offset )
438
492
}
439
493
440
494
obj := & plumbing.MemoryObject {}
@@ -444,7 +498,7 @@ func (s *ObjectStorage) decodeDeltaObjectAt(
444
498
return nil , err
445
499
}
446
500
447
- if _ , _ , err := p .NextObject (w ); err != nil {
501
+ if _ , _ , err := scan .NextObject (w ); err != nil {
448
502
return nil , err
449
503
}
450
504
@@ -515,7 +569,20 @@ func (s *ObjectStorage) buildPackfileIters(
515
569
516
570
// Close closes all opened files.
517
571
func (s * ObjectStorage ) Close () error {
518
- return s .dir .Close ()
572
+ var firstError error
573
+ if s .options .KeepDescriptors || s .options .MaxOpenDescriptors > 0 {
574
+ for _ , packfile := range s .packfiles {
575
+ err := packfile .Close ()
576
+ if firstError == nil && err != nil {
577
+ firstError = err
578
+ }
579
+ }
580
+ }
581
+
582
+ s .packfiles = nil
583
+ s .dir .Close ()
584
+
585
+ return firstError
519
586
}
520
587
521
588
type lazyPackfilesIter struct {
0 commit comments