Commit Diff


commit - c46c1d5a37ed2a2f3626a2b10708eab0864e4795
commit + 6bc0ac427c4a9ee19ec553c4faedfa250054ed10
blob - b012d04b45716766ba498dbcbe70907eb721c37a
blob + f0042f1656fb29b448bd76ea3c06fe318fff02b3
--- regress/compaction/compaction_test.c
+++ regress/compaction/compaction_test.c
@@ -926,6 +926,48 @@ test_compaction_estimate_overflow(void)
 	msglist_free(&messages);
 }
 
+static void
+test_summary_prose_restore(void)
+{
+	static const char prose[] = { 'n', 'o', 't', 'e', '\0', 's' };
+	static const char unmatched[] = "legacy notes without generated blocks";
+	struct compaction_files *files;
+	struct buf summary, out, blocks;
+
+	files = compaction_files_new();
+	CHECK(compaction_files_add(files, COMPACTION_FILE_READ,
+	    "src/a.c", 7) == 0);
+	CHECK(compaction_files_add(files, COMPACTION_FILE_MODIFIED,
+	    "src/b.c", 7) == 0);
+	buf_init(&summary);
+	buf_init(&out);
+	buf_init(&blocks);
+	buf_add(&summary, prose, sizeof(prose));
+	CHECK(compaction_files_append(&summary, files, SIZE_MAX) == 0);
+	CHECK(compaction_summary_prose(&out, summary.data, summary.len,
+	    files) == 0);
+	CHECK(buf_is(&out, prose, sizeof(prose)));
+
+	buf_reset(&out);
+	CHECK(compaction_summary_prose(&out, unmatched,
+	    sizeof(unmatched) - 1, files) == 0);
+	CHECK(buf_is(&out, unmatched, sizeof(unmatched) - 1));
+
+	CHECK(compaction_files_append(&blocks, files, SIZE_MAX) == 0);
+	buf_reset(&out);
+	CHECK(compaction_summary_prose(&out, blocks.data, blocks.len,
+	    files) == 0);
+	CHECK(out.len == 0);
+
+	buf_addstr(&out, "sentinel");
+	CHECK(compaction_summary_prose(&out, NULL, 1, files) == -1);
+	CHECK(out.len == 0);
+	buf_free(&blocks);
+	buf_free(&out);
+	buf_free(&summary);
+	compaction_files_free(files);
+}
+
 int
 main(void)
 {
@@ -948,6 +990,7 @@ main(void)
 	test_cut_plan_turn_boundaries();
 	test_cut_plan_tool_pairs_and_steers();
 	test_compaction_estimate_overflow();
+	test_summary_prose_restore();
 
 	REGRESS_END();
 }
blob - 3d59370f3ab1d0dd03277436d94b589ac3d858e3
blob + a1f1e0d4295718f3f1f6680ef6ab275e8dff11ed
--- src/common/compaction.c
+++ src/common/compaction.c
@@ -879,6 +879,50 @@ fail:
 	return (-1);
 }
 
+int
+compaction_summary_prose(struct buf *out, const void *summary,
+    size_t summary_len, const struct compaction_files *files)
+{
+	const unsigned char	*bytes = summary;
+	struct buf		 blocks, restored;
+	size_t			 suffix;
+
+	if (out == NULL)
+		return (-1);
+	buf_reset(out);
+	if ((summary == NULL && summary_len != 0) || files == NULL)
+		return (-1);
+	buf_init(&blocks);
+	buf_init(&restored);
+	if (compaction_files_append(&blocks, files, SIZE_MAX) == -1)
+		goto fail;
+	if (summary_len == blocks.len &&
+	    (summary_len == 0 || memcmp(summary, blocks.data, blocks.len) == 0))
+		goto publish;
+	if (summary_len >= blocks.len + 2) {
+		suffix = summary_len - blocks.len;
+		if (bytes[suffix - 2] == '\n' && bytes[suffix - 1] == '\n' &&
+		    memcmp(bytes + suffix, blocks.data, blocks.len) == 0) {
+			buf_add(&restored, bytes, suffix - 2);
+			goto publish;
+		}
+	}
+	if (summary_len > 0)
+		buf_add(&restored, summary, summary_len);
+
+publish:
+	if (restored.len > 0)
+		buf_add(out, restored.data, restored.len);
+	buf_free(&restored);
+	buf_free(&blocks);
+	return (0);
+
+fail:
+	buf_free(&restored);
+	buf_free(&blocks);
+	return (-1);
+}
+
 static int
 tool_value_add(struct compact_writer *w, const struct json *json, int value)
 {
blob - 8db76b21a3e3a15dd2517608e8ecdc9bff2359eb
blob + f131b52c05193b6703c061a7f65141b11f2e762d
--- src/common/compaction.h
+++ src/common/compaction.h
@@ -97,6 +97,10 @@ int	compaction_files_get(const struct compaction_files
 int	compaction_files_append(struct buf *, const struct compaction_files *,
 	    size_t);
 
+/* Recover model prose without parsing model text or trusting generated tags. */
+int	compaction_summary_prose(struct buf *, const void *, size_t,
+	    const struct compaction_files *);
+
 /* Estimate one prospective provider request without provider-wire encoding. */
 int	compaction_estimate_request(const void *, size_t,
 	    const struct msglist *, const struct tool_def *, size_t, size_t *);