@@ -47,17 +47,123 @@ func (dw *deltaSelector) ObjectsToPack(hashes []plumbing.Hash) ([]*ObjectToPack,
47
47
func (dw * deltaSelector ) objectsToPack (hashes []plumbing.Hash ) ([]* ObjectToPack , error ) {
48
48
var objectsToPack []* ObjectToPack
49
49
for _ , h := range hashes {
50
- o , err := dw .storer . EncodedObject ( plumbing . AnyObject , h )
50
+ o , err := dw .encodedDeltaObject ( h )
51
51
if err != nil {
52
52
return nil , err
53
53
}
54
54
55
- objectsToPack = append (objectsToPack , newObjectToPack (o ))
55
+ otp := newObjectToPack (o )
56
+ if _ , ok := o .(plumbing.DeltaObject ); ok {
57
+ otp .Original = nil
58
+ }
59
+
60
+ objectsToPack = append (objectsToPack , otp )
61
+ }
62
+
63
+ if err := dw .fixAndBreakChains (objectsToPack ); err != nil {
64
+ return nil , err
56
65
}
57
66
58
67
return objectsToPack , nil
59
68
}
60
69
70
+ func (dw * deltaSelector ) encodedDeltaObject (h plumbing.Hash ) (plumbing.EncodedObject , error ) {
71
+ edos , ok := dw .storer .(storer.DeltaObjectStorer )
72
+ if ! ok {
73
+ return dw .encodedObject (h )
74
+ }
75
+
76
+ return edos .DeltaObject (plumbing .AnyObject , h )
77
+ }
78
+
79
+ func (dw * deltaSelector ) encodedObject (h plumbing.Hash ) (plumbing.EncodedObject , error ) {
80
+ return dw .storer .EncodedObject (plumbing .AnyObject , h )
81
+ }
82
+
83
+ func (dw * deltaSelector ) fixAndBreakChains (objectsToPack []* ObjectToPack ) error {
84
+ m := make (map [plumbing.Hash ]* ObjectToPack , len (objectsToPack ))
85
+ for _ , otp := range objectsToPack {
86
+ m [otp .Hash ()] = otp
87
+ }
88
+
89
+ for _ , otp := range objectsToPack {
90
+ if err := dw .fixAndBreakChainsOne (m , otp ); err != nil {
91
+ return err
92
+ }
93
+ }
94
+
95
+ return nil
96
+ }
97
+
98
+ func (dw * deltaSelector ) fixAndBreakChainsOne (objectsToPack map [plumbing.Hash ]* ObjectToPack , otp * ObjectToPack ) error {
99
+ if ! otp .Object .Type ().IsDelta () {
100
+ return nil
101
+ }
102
+
103
+ // Initial ObjectToPack instances might have a delta assigned to Object
104
+ // but no actual base initially. Once Base is assigned to a delta, it means
105
+ // we already fixed it.
106
+ if otp .Base != nil {
107
+ return nil
108
+ }
109
+
110
+ do , ok := otp .Object .(plumbing.DeltaObject )
111
+ if ! ok {
112
+ // if this is not a DeltaObject, then we cannot retrieve its base,
113
+ // so we have to break the delta chain here.
114
+ return dw .undeltify (otp )
115
+ }
116
+
117
+ base , ok := objectsToPack [do .BaseHash ()]
118
+ if ! ok {
119
+ // The base of the delta is not in our list of objects to pack, so
120
+ // we break the chain.
121
+ return dw .undeltify (otp )
122
+ }
123
+
124
+ if base .Size () <= otp .Size () {
125
+ // Bases should be bigger
126
+ return dw .undeltify (otp )
127
+ }
128
+
129
+ if err := dw .fixAndBreakChainsOne (objectsToPack , base ); err != nil {
130
+ return err
131
+ }
132
+
133
+ otp .SetDelta (base , otp .Object )
134
+ return nil
135
+ }
136
+
137
+ func (dw * deltaSelector ) restoreOriginal (otp * ObjectToPack ) error {
138
+ if otp .Original != nil {
139
+ return nil
140
+ }
141
+
142
+ if ! otp .Object .Type ().IsDelta () {
143
+ return nil
144
+ }
145
+
146
+ obj , err := dw .encodedObject (otp .Hash ())
147
+ if err != nil {
148
+ return err
149
+ }
150
+
151
+ otp .Original = obj
152
+ return nil
153
+ }
154
+
155
+ // undeltify undeltifies an *ObjectToPack by retrieving the original object from
156
+ // the storer and resetting it.
157
+ func (dw * deltaSelector ) undeltify (otp * ObjectToPack ) error {
158
+ if err := dw .restoreOriginal (otp ); err != nil {
159
+ return err
160
+ }
161
+
162
+ otp .Object = otp .Original
163
+ otp .Depth = 0
164
+ return nil
165
+ }
166
+
61
167
func (dw * deltaSelector ) sort (objectsToPack []* ObjectToPack ) {
62
168
sort .Sort (byTypeAndSize (objectsToPack ))
63
169
}
@@ -66,15 +172,24 @@ func (dw *deltaSelector) walk(objectsToPack []*ObjectToPack) error {
66
172
for i := 0 ; i < len (objectsToPack ); i ++ {
67
173
target := objectsToPack [i ]
68
174
69
- // We only want to create deltas from specific types
70
- if ! applyDelta [target .Original .Type ()] {
175
+ // If we already have a delta, we don't try to find a new one for this
176
+ // object. This happens when a delta is set to be reused from an existing
177
+ // packfile.
178
+ if target .IsDelta () {
179
+ continue
180
+ }
181
+
182
+ // We only want to create deltas from specific types.
183
+ if ! applyDelta [target .Type ()] {
71
184
continue
72
185
}
73
186
74
187
for j := i - 1 ; j >= 0 ; j -- {
75
188
base := objectsToPack [j ]
76
189
// Objects must use only the same type as their delta base.
77
- if base .Original .Type () != target .Original .Type () {
190
+ // Since objectsToPack is sorted by type and size, once we find
191
+ // a different type, we know we won't find more of them.
192
+ if base .Type () != target .Type () {
78
193
break
79
194
}
80
195
@@ -89,7 +204,7 @@ func (dw *deltaSelector) walk(objectsToPack []*ObjectToPack) error {
89
204
90
205
func (dw * deltaSelector ) tryToDeltify (base , target * ObjectToPack ) error {
91
206
// If the sizes are radically different, this is a bad pairing.
92
- if target .Original . Size () < base . Original .Size ()>> 4 {
207
+ if target .Size () < base .Size ()>> 4 {
93
208
return nil
94
209
}
95
210
@@ -106,10 +221,20 @@ func (dw *deltaSelector) tryToDeltify(base, target *ObjectToPack) error {
106
221
}
107
222
108
223
// If we have to insert a lot to make this work, find another.
109
- if base .Original . Size ()- target . Object .Size () > msz {
224
+ if base .Size ()- target .Size () > msz {
110
225
return nil
111
226
}
112
227
228
+ // Original object might not be present if we're reusing a delta, so we
229
+ // ensure it is restored.
230
+ if err := dw .restoreOriginal (target ); err != nil {
231
+ return err
232
+ }
233
+
234
+ if err := dw .restoreOriginal (base ); err != nil {
235
+ return err
236
+ }
237
+
113
238
// Now we can generate the delta using originals
114
239
delta , err := GetDelta (base .Original , target .Original )
115
240
if err != nil {
@@ -162,13 +287,13 @@ func (a byTypeAndSize) Len() int { return len(a) }
162
287
func (a byTypeAndSize ) Swap (i , j int ) { a [i ], a [j ] = a [j ], a [i ] }
163
288
164
289
func (a byTypeAndSize ) Less (i , j int ) bool {
165
- if a [i ].Object . Type () < a [j ]. Object .Type () {
290
+ if a [i ].Type () < a [j ].Type () {
166
291
return false
167
292
}
168
293
169
- if a [i ].Object . Type () > a [j ]. Object .Type () {
294
+ if a [i ].Type () > a [j ].Type () {
170
295
return true
171
296
}
172
297
173
- return a [i ].Object . Size () > a [j ]. Object .Size ()
298
+ return a [i ].Size () > a [j ].Size ()
174
299
}
0 commit comments