2626#include " iceberg/manifest/manifest_entry.h"
2727#include " iceberg/manifest/manifest_util_internal.h"
2828#include " iceberg/snapshot.h"
29- #include " iceberg/table.h"
29+ #include " iceberg/table.h" // IWYU pragma: keep
3030#include " iceberg/table_metadata.h"
3131#include " iceberg/table_properties.h"
3232#include " iceberg/transaction.h"
@@ -58,7 +58,7 @@ FastAppend& FastAppend::AppendFile(const std::shared_ptr<DataFile>& file) {
5858 auto [iter, inserted] = data_files.insert (file);
5959 if (inserted) {
6060 has_new_files_ = true ;
61- ICEBERG_BUILDER_RETURN_IF_ERROR (summary_ .AddedFile (*spec, *file));
61+ ICEBERG_BUILDER_RETURN_IF_ERROR (added_data_files_summary_ .AddedFile (*spec, *file));
6262 }
6363
6464 return *this ;
@@ -75,11 +75,13 @@ FastAppend& FastAppend::AppendManifest(const ManifestFile& manifest) {
7575 " Sequence number must be assigned during commit" );
7676
7777 if (can_inherit_snapshot_id () && manifest.added_snapshot_id == kInvalidSnapshotId ) {
78- summary_ .AddedManifest (manifest);
78+ appended_manifests_summary_ .AddedManifest (manifest);
7979 append_manifests_.push_back (manifest);
8080 } else {
8181 // The manifest must be rewritten with this update's snapshot ID
82- ICEBERG_BUILDER_ASSIGN_OR_RETURN (auto copied_manifest, CopyManifest (manifest));
82+ ICEBERG_BUILDER_ASSIGN_OR_RETURN (auto copied_manifest,
83+ CopyManifest (manifest, /* update_summary=*/ true ));
84+ append_manifests_to_copy_.push_back (manifest);
8385 rewritten_append_manifests_.push_back (std::move (copied_manifest));
8486 }
8587
@@ -93,6 +95,16 @@ Result<std::vector<ManifestFile>> FastAppend::Apply(
9395 std::vector<ManifestFile> manifests;
9496
9597 ICEBERG_ASSIGN_OR_RAISE (auto new_written_manifests, WriteNewManifests ());
98+ // A retry cleanup deletes copied append manifests and clears the rewritten
99+ // list; rebuild them from the original appended manifests before re-applying.
100+ if (rewritten_append_manifests_.empty () && !append_manifests_to_copy_.empty ()) {
101+ for (const auto & manifest : append_manifests_to_copy_) {
102+ ICEBERG_ASSIGN_OR_RAISE (auto copied_manifest,
103+ CopyManifest (manifest, /* update_summary=*/ false ));
104+ rewritten_append_manifests_.push_back (std::move (copied_manifest));
105+ }
106+ }
107+
96108 manifests.reserve (new_written_manifests.size () + append_manifests_.size () +
97109 rewritten_append_manifests_.size ());
98110 if (!new_written_manifests.empty ()) {
@@ -122,15 +134,31 @@ Result<std::vector<ManifestFile>> FastAppend::Apply(
122134 snapshot_manifests.end ());
123135 }
124136
137+ manifest_count_summary_ =
138+ BuildManifestCountSummary (manifests, /* replaced_manifests_count=*/ 0 );
139+
125140 return manifests;
126141}
127142
128143std::unordered_map<std::string, std::string> FastAppend::Summary () {
144+ summary_.Clear ();
129145 summary_.SetPartitionSummaryLimit (
130146 base ().properties .Get (TableProperties::kWritePartitionSummaryLimit ));
147+ summary_.Merge (added_data_files_summary_);
148+ summary_.Merge (appended_manifests_summary_);
149+ for (const auto & [property, value] : custom_summary_properties_) {
150+ summary_.Set (property, value);
151+ }
152+ summary_.Merge (manifest_count_summary_);
131153 return summary_.Build ();
132154}
133155
156+ void FastAppend::SetSummaryProperty (const std::string& property,
157+ const std::string& value) {
158+ custom_summary_properties_[property] = value;
159+ SnapshotUpdate::SetSummaryProperty (property, value);
160+ }
161+
134162Status FastAppend::CleanUncommitted (const std::unordered_set<std::string>& committed) {
135163 // Clean up new manifests that were written but not committed
136164 if (!new_manifests_.empty ()) {
@@ -151,24 +179,26 @@ Status FastAppend::CleanUncommitted(const std::unordered_set<std::string>& commi
151179 std::ignore = DeleteFile (manifest.manifest_path );
152180 }
153181 }
182+ rewritten_append_manifests_.clear ();
154183 }
155184 return {};
156185}
157186
158187bool FastAppend::CleanupAfterCommit () const {
159- // Cleanup after committing is disabled for FastAppend unless there are
160- // rewritten_append_manifests_ because:
161- // 1.) Appended manifests are never rewritten
188+ // Cleanup after committing is disabled for FastAppend unless append manifests
189+ // were copied or need to be copied on retry because:
190+ // 1.) Directly appended manifests are never rewritten
162191 // 2.) Manifests which are written out as part of AppendFile are already cleaned
163192 // up between commit attempts in WriteNewManifests
164- return !rewritten_append_manifests_.empty ();
193+ return !rewritten_append_manifests_.empty () || !append_manifests_to_copy_. empty () ;
165194}
166195
167196Result<std::shared_ptr<PartitionSpec>> FastAppend::Spec (int32_t spec_id) {
168197 return base ().PartitionSpecById (spec_id);
169198}
170199
171- Result<ManifestFile> FastAppend::CopyManifest (const ManifestFile& manifest) {
200+ Result<ManifestFile> FastAppend::CopyManifest (const ManifestFile& manifest,
201+ bool update_summary) {
172202 const TableMetadata& current = base ();
173203 ICEBERG_ASSIGN_OR_RAISE (auto schema, current.Schema ());
174204 ICEBERG_ASSIGN_OR_RAISE (auto spec,
@@ -180,7 +210,8 @@ Result<ManifestFile> FastAppend::CopyManifest(const ManifestFile& manifest) {
180210
181211 // Copy the manifest with the new snapshot ID.
182212 return CopyAppendManifest (manifest, ctx_->table ->io (), schema, spec, snapshot_id,
183- new_manifest_path, current.format_version , &summary_);
213+ new_manifest_path, current.format_version ,
214+ update_summary ? &appended_manifests_summary_ : nullptr );
184215}
185216
186217Result<std::vector<ManifestFile>> FastAppend::WriteNewManifests () {
0 commit comments