@@ -56,10 +56,12 @@ type Decoder struct {
56
56
o storer.EncodedObjectStorer
57
57
tx storer.Transaction
58
58
59
- isDecoded bool
60
- offsetToHash map [int64 ]plumbing.Hash
61
- hashToOffset map [plumbing.Hash ]int64
62
- crcs map [plumbing.Hash ]uint32
59
+ isDecoded bool
60
+
61
+ // hasBuiltIndex indicates if the index is fully built or not. If it is not,
62
+ // will be built incrementally while decoding.
63
+ hasBuiltIndex bool
64
+ idx * Index
63
65
64
66
offsetToType map [int64 ]plumbing.ObjectType
65
67
decoderType plumbing.ObjectType
@@ -102,10 +104,7 @@ func NewDecoderForType(s *Scanner, o storer.EncodedObjectStorer,
102
104
s : s ,
103
105
o : o ,
104
106
105
- offsetToHash : make (map [int64 ]plumbing.Hash , 0 ),
106
- hashToOffset : make (map [plumbing.Hash ]int64 , 0 ),
107
- crcs : make (map [plumbing.Hash ]uint32 , 0 ),
108
-
107
+ idx : NewIndex (0 ),
109
108
offsetToType : make (map [int64 ]plumbing.ObjectType , 0 ),
110
109
decoderType : t ,
111
110
@@ -139,6 +138,11 @@ func (d *Decoder) doDecode() error {
139
138
return err
140
139
}
141
140
141
+ if ! d .hasBuiltIndex {
142
+ d .idx = NewIndex (int (count ))
143
+ }
144
+ defer func () { d .hasBuiltIndex = true }()
145
+
142
146
_ , isTxStorer := d .o .(storer.Transactioner )
143
147
switch {
144
148
case d .o == nil :
@@ -218,13 +222,22 @@ func (d *Decoder) DecodeObject() (plumbing.EncodedObject, error) {
218
222
}
219
223
220
224
func (d * Decoder ) decodeIfSpecificType (h * ObjectHeader ) (plumbing.EncodedObject , error ) {
221
- var realType plumbing.ObjectType
222
- var err error
225
+ var (
226
+ obj plumbing.EncodedObject
227
+ realType plumbing.ObjectType
228
+ err error
229
+ )
223
230
switch h .Type {
224
231
case plumbing .OFSDeltaObject :
225
232
realType , err = d .ofsDeltaType (h .OffsetReference )
226
233
case plumbing .REFDeltaObject :
227
234
realType , err = d .refDeltaType (h .Reference )
235
+ if err == plumbing .ErrObjectNotFound {
236
+ obj , err = d .decodeByHeader (h )
237
+ if err != nil {
238
+ realType = obj .Type ()
239
+ }
240
+ }
228
241
default :
229
242
realType = h .Type
230
243
}
@@ -236,6 +249,10 @@ func (d *Decoder) decodeIfSpecificType(h *ObjectHeader) (plumbing.EncodedObject,
236
249
d .offsetToType [h .Offset ] = realType
237
250
238
251
if d .decoderType == realType {
252
+ if obj != nil {
253
+ return obj , nil
254
+ }
255
+
239
256
return d .decodeByHeader (h )
240
257
}
241
258
@@ -252,16 +269,12 @@ func (d *Decoder) ofsDeltaType(offset int64) (plumbing.ObjectType, error) {
252
269
}
253
270
254
271
func (d * Decoder ) refDeltaType (ref plumbing.Hash ) (plumbing.ObjectType , error ) {
255
- if o , ok := d .hashToOffset [ref ]; ok {
256
- return d .ofsDeltaType (o )
257
- }
258
-
259
- obj , err := d .o .EncodedObject (plumbing .AnyObject , ref )
260
- if err != nil {
261
- return plumbing .InvalidObject , err
272
+ e , ok := d .idx .LookupHash (ref )
273
+ if ! ok {
274
+ return plumbing .InvalidObject , plumbing .ErrObjectNotFound
262
275
}
263
276
264
- return obj . Type (), nil
277
+ return d . ofsDeltaType ( int64 ( e . Offset ))
265
278
}
266
279
267
280
func (d * Decoder ) decodeByHeader (h * ObjectHeader ) (plumbing.EncodedObject , error ) {
@@ -285,9 +298,9 @@ func (d *Decoder) decodeByHeader(h *ObjectHeader) (plumbing.EncodedObject, error
285
298
return obj , err
286
299
}
287
300
288
- hash := obj . Hash ()
289
- d . setOffset ( hash , h .Offset )
290
- d . setCRC ( hash , crc )
301
+ if ! d . hasBuiltIndex {
302
+ d . idx . Add ( obj . Hash (), uint64 ( h .Offset ), crc )
303
+ }
291
304
292
305
return obj , nil
293
306
}
@@ -365,10 +378,10 @@ func (d *Decoder) fillOFSDeltaObjectContent(obj plumbing.EncodedObject, offset i
365
378
return 0 , err
366
379
}
367
380
368
- h := d .offsetToHash [ offset ]
381
+ e , ok := d .idx . LookupOffset ( uint64 ( offset ))
369
382
var base plumbing.EncodedObject
370
- if h != plumbing . ZeroHash {
371
- base = d .cache .Get (h )
383
+ if ok {
384
+ base = d .cache .Get (e . Hash )
372
385
}
373
386
374
387
if base == nil {
@@ -385,31 +398,22 @@ func (d *Decoder) fillOFSDeltaObjectContent(obj plumbing.EncodedObject, offset i
385
398
return crc , err
386
399
}
387
400
388
- func (d * Decoder ) setOffset (h plumbing.Hash , offset int64 ) {
389
- d .offsetToHash [offset ] = h
390
- d .hashToOffset [h ] = offset
391
- }
392
-
393
- func (d * Decoder ) setCRC (h plumbing.Hash , crc uint32 ) {
394
- d .crcs [h ] = crc
395
- }
396
-
397
401
func (d * Decoder ) recallByOffset (o int64 ) (plumbing.EncodedObject , error ) {
398
402
if d .s .IsSeekable {
399
403
return d .DecodeObjectAt (o )
400
404
}
401
405
402
- if h , ok := d .offsetToHash [ o ] ; ok {
403
- return d .recallByHashNonSeekable (h )
406
+ if e , ok := d .idx . LookupOffset ( uint64 ( o )) ; ok {
407
+ return d .recallByHashNonSeekable (e . Hash )
404
408
}
405
409
406
410
return nil , plumbing .ErrObjectNotFound
407
411
}
408
412
409
413
func (d * Decoder ) recallByHash (h plumbing.Hash ) (plumbing.EncodedObject , error ) {
410
414
if d .s .IsSeekable {
411
- if o , ok := d .hashToOffset [ h ] ; ok {
412
- return d .DecodeObjectAt (o )
415
+ if e , ok := d .idx . LookupHash ( h ) ; ok {
416
+ return d .DecodeObjectAt (int64 ( e . Offset ) )
413
417
}
414
418
}
415
419
@@ -432,22 +436,20 @@ func (d *Decoder) recallByHashNonSeekable(h plumbing.Hash) (obj plumbing.Encoded
432
436
return nil , plumbing .ErrObjectNotFound
433
437
}
434
438
435
- // SetOffsets sets the offsets, required when using the method DecodeObjectAt,
436
- // without decoding the full packfile
437
- func (d * Decoder ) SetOffsets (offsets map [plumbing.Hash ]int64 ) {
438
- d .hashToOffset = offsets
439
- }
440
-
441
- // Offsets returns the objects read offset, Decode method should be called
442
- // before to calculate the Offsets
443
- func (d * Decoder ) Offsets () map [plumbing.Hash ]int64 {
444
- return d .hashToOffset
439
+ // SetIndex sets an index for the packfile. It is recommended to set this.
440
+ // The index might be read from a file or reused from a previous Decoder usage
441
+ // (see Index function).
442
+ func (d * Decoder ) SetIndex (idx * Index ) {
443
+ d .hasBuiltIndex = true
444
+ d .idx = idx
445
445
}
446
446
447
- // CRCs returns the CRC-32 for each read object. Decode method should be called
448
- // before to calculate the CRCs
449
- func (d * Decoder ) CRCs () map [plumbing.Hash ]uint32 {
450
- return d .crcs
447
+ // Index returns the index for the packfile. If index was set with SetIndex,
448
+ // Index will return it. Otherwise, it will return an index that is built while
449
+ // decoding. If neither SetIndex was called with a full index or Decode called
450
+ // for the whole packfile, then the returned index will be incomplete.
451
+ func (d * Decoder ) Index () * Index {
452
+ return d .idx
451
453
}
452
454
453
455
// Close closes the Scanner. usually this mean that the whole reader is read and
0 commit comments