Commit 92d069a064dddece82e3a8b59ed0e08336dcb001
Improve fetch
- Use repo.hasObjectQuick - For getting objects, use set of haves rather than a single common hash - Don't send objects that are reachable from objects the client already hasCharles Lehner committed on 10/11/2016, 2:09:14 AM
Parent: 9f6b7a97b920fe19a6c5b5cde35a13230b4e1b9a
Files changed
index.js | changed |
index.js | |||
---|---|---|---|
@@ -62,11 +62,8 @@ | |||
62 | 62 … | // references: | |
63 | 63 … | // git/documentation/technical/pack-protocol.txt | |
64 | 64 … | // git/documentation/technical/protocol-capabilities.txt | |
65 | 65 … | function uploadPack(read, repo, options) { | |
66 | - /* multi_ack thin-pack side-band side-band-64k ofs-delta shallow no-progress | ||
67 | - * include-tag multi_ack_detailed | ||
68 | - * agent=git/2.7.0 */ | ||
69 | 66 … | var sendRefs = receivePackHeader([ | |
70 | 67 … | agentCap, | |
71 | 68 … | ], repo.refs(), repo.symrefs()) | |
72 | 69 … | ||
@@ -75,9 +72,9 @@ | |||
75 | 72 … | verbosity: options.verbosity | |
76 | 73 … | }) | |
77 | 74 … | var readWantHave = lines.haves() | |
78 | 75 … | var acked | |
79 | - var commonHash | ||
76 … | + var haves = {} | ||
80 | 77 … | var sendPack | |
81 | 78 … | var wants = {} | |
82 | 79 … | var shallows = {} | |
83 | 80 … | var aborted | |
@@ -114,14 +111,12 @@ | |||
114 | 111 … | function readHave(abort, cb) { | |
115 | 112 … | // Read upload haves (haves list). | |
116 | 113 … | // On first obj-id that we have, ACK | |
117 | 114 … | // If we have none, NAK. | |
118 | - // TODO: implement multi_ack_detailed | ||
119 | - // FIXME! | ||
120 | 115 … | if (abort) return | |
121 | 116 … | if (gotHaves) return cb(true) | |
122 | 117 … | readWantHave(null, function next(end, have) { | |
123 | - if (end === true) { | ||
118 … | + if (end === true) { // done | ||
124 | 119 … | gotHaves = true | |
125 | 120 … | if (!acked) { | |
126 | 121 … | cb(null, 'NAK') | |
127 | 122 … | } else { | |
@@ -137,19 +132,24 @@ | |||
137 | 132 … | } else if (end) | |
138 | 133 … | cb(end) | |
139 | 134 … | else if (have.type != 'have') | |
140 | 135 … | cb(new Error('Unknown have' + JSON.stringify(have))) | |
141 | - else if (acked) | ||
142 | - readWantHave(null, next) | ||
143 | - else | ||
144 | - repo.hasObjectFromAny(have.hash, function (err, haveIt) { | ||
145 | - if (err) return cb(err) | ||
146 | - if (!haveIt) | ||
147 | - return readWantHave(null, next) | ||
148 | - commonHash = haveIt | ||
149 | - acked = true | ||
150 | - cb(null, 'ACK ' + have.hash) | ||
151 | - }) | ||
136 … | + else { | ||
137 … | + haves[have.hash] = true | ||
138 … | + if (acked) { | ||
139 … | + readWantHave(null, next) | ||
140 … | + } else if (repo.hasObjectQuick) { | ||
141 … | + gotHasObject(null, repo.hasObjectQuick(have.hash)) | ||
142 … | + } else { | ||
143 … | + repo.hasObjectFromAny(have.hash, gotHasObject) | ||
144 … | + } | ||
145 … | + } | ||
146 … | + function gotHasObject(err, haveIt) { | ||
147 … | + if (err) return cb(err) | ||
148 … | + if (!haveIt) return readWantHave(null, next) | ||
149 … | + acked = true | ||
150 … | + cb(null, 'ACK ' + have.hash) | ||
151 … | + } | ||
152 | 152 … | }) | |
153 | 153 … | } | |
154 | 154 … | ||
155 | 155 … | function readPack(abort, cb) { | |
@@ -157,12 +157,12 @@ | |||
157 | 157 … | if (sendPack) return sendPack(abort, cb) | |
158 | 158 … | // send pack file to client | |
159 | 159 … | if (!hasWants) return cb(true) | |
160 | 160 … | if (options.verbosity >= 2) { | |
161 | - console.error('common', commonHash, 'wants', wants) | ||
161 … | + console.error('wants', wants) | ||
162 | 162 … | } | |
163 | 163 … | // TODO: show progress during getObjects | |
164 | - getObjects(repo, commonHash, wants, shallows, | ||
164 … | + getObjects(repo, wants, shallows, haves, | ||
165 | 165 … | function (err, numObjects, readObjects) { | |
166 | 166 … | if (err) return cb(err) | |
167 | 167 … | // var progress = progressObjects(options) | |
168 | 168 … | // progress.setNumObjects(numObjects) | |
@@ -224,46 +224,68 @@ | |||
224 | 224 … | } | |
225 | 225 … | return progress | |
226 | 226 … | } | |
227 | 227 … | ||
228 | -function getObjects(repo, commonHash, heads, shallows, cb) { | ||
229 | - // get objects from commonHash to each head, inclusive. | ||
230 | - // if commonHash is falsy, use root | ||
228 … | +function getObjects(repo, heads, shallows, haves, cb) { | ||
229 … | + // get objects from heads back to haves | ||
231 | 230 … | var objects = [] | |
232 | 231 … | var objectsAdded = {} | |
232 … | + var exclude = {} | ||
233 | 233 … | var done = multicb({pluck: 1}) | |
234 | 234 … | var ended | |
235 | 235 … | ||
236 | - // walk back from heads until get to commonHash | ||
236 … | + // walk back from heads until get to a have | ||
237 | 237 … | for (var hash in heads) | |
238 | 238 … | addObject(hash, done()) | |
239 | 239 … | ||
240 | - // TODO: only add new objects | ||
241 | - | ||
242 | 240 … | function addObject(hash, cb) { | |
243 | 241 … | if (ended) return cb(ended) | |
244 | - if (hash in objectsAdded || hash == commonHash) return cb() | ||
245 | - objectsAdded[hash] = true | ||
242 … | + if (hash in objectsAdded || hash in exclude) return cb() | ||
243 … | + if (hash in haves) return removeObject(hash, cb) | ||
244 … | + var i = objectsAdded[hash] = objects.length++ | ||
246 | 245 … | repo.getObjectFromAny(hash, function (err, object) { | |
247 | 246 … | if (err) return cb(err) | |
247 … | + if (hash in exclude) return cb() | ||
248 | 248 … | if (object.type == 'blob') { | |
249 | - objects.push(object) | ||
249 … | + objects[i] = object | ||
250 | 250 … | cb() | |
251 | 251 … | } else { | |
252 | 252 … | // object must be read twice, so buffer it | |
253 | 253 … | bufferObject(object, function (err, object) { | |
254 | 254 … | if (err) return cb(err) | |
255 | - objects.push(object) | ||
256 | - var hashes = getObjectLinks(object) | ||
255 … | + objects[i] = object | ||
256 … | + var hashes = getObjectLinks(object, true) | ||
257 | 257 … | for (var sha1 in hashes) | |
258 | 258 … | addObject(sha1, done()) | |
259 | 259 … | cb() | |
260 | 260 … | }) | |
261 | 261 … | } | |
262 | 262 … | }) | |
263 | 263 … | } | |
264 | 264 … | ||
265 … | + function removeObject(hash, cb) { | ||
266 … | + // when reach a have, get what trees/blobs it points to | ||
267 … | + // and exclude them | ||
268 … | + if (ended) return cb(ended) | ||
269 … | + if (hash in exclude) return cb() | ||
270 … | + exclude[hash] = true | ||
271 … | + var i = objectsAdded[hash] | ||
272 … | + if (i >= 0) objects[i] = null | ||
273 … | + repo.getObjectFromAny(hash, function (err, object) { | ||
274 … | + if (err) return cb(err) | ||
275 … | + if (object.type === 'blob') cb() | ||
276 … | + else bufferObject(object, function (err, object) { | ||
277 … | + if (err) return cb(err) | ||
278 … | + var hashes = getObjectLinks(object, false) | ||
279 … | + for (var sha1 in hashes) | ||
280 … | + removeObject(sha1, done()) | ||
281 … | + cb() | ||
282 … | + }) | ||
283 … | + }) | ||
284 … | + } | ||
285 … | + | ||
265 | 286 … | done(function (err) { | |
287 … | + objects = objects.filter(Boolean) | ||
266 | 288 … | if (err) return cb(err) | |
267 | 289 … | // console.error(objects.reduce(function (n, obj) { return obj.length + n}, 0) + ' bytes') | |
268 | 290 … | cb(null, objects.length, pull.values(objects)) | |
269 | 291 … | }) | |
@@ -285,17 +307,17 @@ | |||
285 | 307 … | ) | |
286 | 308 … | } | |
287 | 309 … | ||
288 | 310 … | // get hashes of git objects linked to from other git objects | |
289 | -function getObjectLinks(object, cb) { | ||
311 … | +function getObjectLinks(object, includeParentCommits) { | ||
290 | 312 … | switch (object.type) { | |
291 | 313 … | case 'blob': | |
292 | 314 … | return {} | |
293 | 315 … | case 'tree': | |
294 | 316 … | return getTreeLinks(object.data) | |
317 … | + case 'commit': | ||
295 | 318 … | case 'tag': | |
296 | - case 'commit': | ||
297 | - return getCommitOrTagLinks(object.data) | ||
319 … | + return getCommitOrTagLinks(object.data, includeParentCommits) | ||
298 | 320 … | } | |
299 | 321 … | } | |
300 | 322 … | ||
301 | 323 … | function getTreeLinks(buf) { | |
@@ -312,17 +334,18 @@ | |||
312 | 334 … | } | |
313 | 335 … | return links | |
314 | 336 … | } | |
315 | 337 … | ||
316 | -function getCommitOrTagLinks(buf) { | ||
338 … | +function getCommitOrTagLinks(buf, includeParents) { | ||
317 | 339 … | var lines = buf.toString('utf8').split('\n') | |
318 | 340 … | var links = {} | |
319 | 341 … | // iterate until reach blank line (indicating start of commit/tag body) | |
320 | 342 … | for (var i = 0; lines[i]; i++) { | |
321 | 343 … | var args = lines[i].split(' ') | |
322 | 344 … | switch (args[0]) { | |
345 … | + case 'parent': | ||
346 … | + if (!includeParents) continue | ||
323 | 347 … | case 'tree': | |
324 | - case 'parent': | ||
325 | 348 … | case 'object': | |
326 | 349 … | var hash = args[1] | |
327 | 350 … | if (!(hash in links)) | |
328 | 351 … | links[hash] = true | |
@@ -330,13 +353,8 @@ | |||
330 | 353 … | } | |
331 | 354 … | return links | |
332 | 355 … | } | |
333 | 356 … | ||
334 | -/* | ||
335 | -TODO: investigate capabilities | ||
336 | -report-status delete-refs side-band-64k quiet atomic ofs-delta | ||
337 | -*/ | ||
338 | - | ||
339 | 357 … | // Get a line for each ref that we have. The first line also has capabilities. | |
340 | 358 … | // Wrap with pktLine.encode. | |
341 | 359 … | function receivePackHeader(capabilities, refSource, symrefs) { | |
342 | 360 … | var first = true |
Built with git-ssb-web