| 836 | }; |
| 837 | |
| 838 | Status MergeBundles(Env* env, gtl::ArraySlice<tstring> prefixes, |
| 839 | StringPiece merged_prefix) { |
| 840 | // Merges all metadata tables. |
| 841 | // TODO(zhifengc): KeyValue sorter if it becomes too big. |
| 842 | MergeState merge; |
| 843 | Status status = env->CreateDir(string(io::Dirname(merged_prefix))); |
| 844 | if (!status.ok() && !errors::IsAlreadyExists(status)) return status; |
| 845 | for (int i = 0; i < prefixes.size(); ++i) { |
| 846 | TF_RETURN_IF_ERROR(MergeOneBundle(env, prefixes[i], &merge)); |
| 847 | } |
| 848 | |
| 849 | TF_RETURN_IF_ERROR(FixMergeHashTableBundles(&merge)); |
| 850 | |
| 851 | // Renames data files to contain the merged bundle prefix. |
| 852 | for (const auto& p : merge.shard_ids) { |
| 853 | VLOG(1) << "Renaming " << p.first << " to " |
| 854 | << DataFilename(merged_prefix, p.second, merge.shard_ids.size()); |
| 855 | TF_RETURN_IF_ERROR(env->RenameFile( |
| 856 | p.first, |
| 857 | DataFilename(merged_prefix, p.second, merge.shard_ids.size()))); |
| 858 | } |
| 859 | |
| 860 | // Writes the final metadata table under the merged prefix. |
| 861 | std::unique_ptr<WritableFile> merged_metadata; |
| 862 | TF_RETURN_IF_ERROR( |
| 863 | env->NewWritableFile(MetaFilename(merged_prefix), &merged_metadata)); |
| 864 | { |
| 865 | table::TableBuilder builder(TableBuilderOptions(), merged_metadata.get()); |
| 866 | // Header entry. |
| 867 | BundleHeaderProto header; |
| 868 | header.set_num_shards(merge.num_shards); |
| 869 | header.set_endianness(merge.endianness); |
| 870 | *header.mutable_version() = merge.version; |
| 871 | builder.Add(kHeaderEntryKey, header.SerializeAsString()); |
| 872 | // All others. |
| 873 | for (const auto& p : merge.entries) { |
| 874 | builder.Add(p.first, p.second.SerializeAsString()); |
| 875 | } |
| 876 | status = builder.Finish(); |
| 877 | } |
| 878 | status.Update(merged_metadata->Close()); |
| 879 | if (!status.ok()) return status; |
| 880 | VLOG(1) << "Merged bundles to:" << merged_prefix; |
| 881 | |
| 882 | // Cleanup: best effort based and ignores errors. |
| 883 | for (const string& prefix : prefixes) { |
| 884 | env->DeleteFile(MetaFilename(prefix)).IgnoreError(); |
| 885 | } |
| 886 | return status; |
| 887 | } |
| 888 | |
| 889 | // Interface for reading a tensor bundle. |
| 890 | |