17b5a2a8f939

3.4.1: a steal refuses a bundle that does not end in 'end 0', so a dropped connection cannot pass for a whole repo

time
2026-10-03 17:46 UTC · 1 week ago
machine
Junes-MacBook-Pro.local
agent
claude-opus-5-5
session
faster whole-repo steal
parent
c01f0cf14856
4 files VERSION+1 −1src/exchange/exchange_test.v+3 −2src/exchange/steal.v+7 −2v.mod+1 −1
VERSION+1 −1
@@ -1 +1 @@1-3.4.01+3.4.1

view file

src/exchange/exchange_test.v+3 −2
@@ -1633,12 +1633,13 @@16331633 16341634 fn test_a_bundle_lands_each_entry_and_refuses_a_cut_or_foreign_one() {16351635 	mut fetched := Fetched{}1636-	take_bundle(mut fetched, 'objects/aa 3\nabcobjects/bb 0\n'.bytes())!1636+	take_bundle(mut fetched, 'objects/aa 3\nabcobjects/bb 0\nend 0\n'.bytes())!16371637 	assert fetched.repo_objects == {16381638 		'aa': 'abc'.bytes()16391639 		'bb': []u8{}16401640 	}1641-	for cut in ['objects/aa 4\nabc', 'objects/aa 3', 'objects/aa x\nabc', 'releases/v1 1\nx'] {1641+	for cut in ['objects/aa 3\nabc', 'objects/aa 4\nabc', 'objects/aa 3', 'objects/aa x\nabc',1642+		'releases/v1 1\nx', 'end 0\nobjects/aa 3\nabc'] {16421643 		take_bundle(mut fetched, cut.bytes()) or { continue }16431644 		assert false, cut16441645 	}

view file

src/exchange/steal.v+7 −2
@@ -584,8 +584,9 @@584584 	return fetched585585 }586586 587-// take_bundle splits §22.7's bundle — `<key> <length>\n` and then that many bytes, over and over —588-// into what one GET of each key would have returned.587+// take_bundle splits §22.7's bundle — `<key> <length>\n` and then that many bytes, over and over,588+// until `end 0` — into what one GET of each key would have returned. A connection that drops589+// between two entries still looks like a whole bundle, so only the end line proves it arrived.589590 fn take_bundle(mut fetched Fetched, body []u8) ! {590591 	mut at := 0591592 	for at < body.len {@@ -598,6 +599,9 @@598599 			return error('the bundle ends part way through an entry')599600 		}600601 		header := body[at..newline].bytestr()602+		if header == 'end 0' && newline + 1 == body.len {603+			return604+		}601605 		length := strconv.atoi(header.all_after(' '))!602606 		start := newline + 1603607 		if length < 0 || length > body.len - start {@@ -606,6 +610,7 @@606610 		take(mut fetched, header.all_before(' '), body[start..start + length])!607611 		at = start + length608612 	}613+	return error('the bundle was cut short — try the steal again')609614 }610615 611616 // take files one fetched key, relative to the repo: an object, a save or an event.

view file

v.mod+1 −1
@@ -1,6 +1,6 @@11 Module {22 	name: 'koh3'3-	version: '3.4.0'3+	version: '3.4.1'44 	description: 'One SQLite file per repo, one line of history.'55 	license: 'MIT'66 }

view file