Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(clp-core): Add the write path for single-file archives. #646

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a5ef64f
first draft
davemarco Dec 28, 2024
615fafd
small changes
davemarco Dec 28, 2024
b84c2da
small changes
davemarco Dec 28, 2024
d1ec9fe
refactor
davemarco Dec 28, 2024
869f1b3
refactor
davemarco Dec 28, 2024
d84c002
refactor
davemarco Dec 28, 2024
f4136f8
refactor
davemarco Dec 28, 2024
6bbf12e
refactor
davemarco Dec 28, 2024
5c75147
remove extra line
davemarco Dec 28, 2024
c1f12df
fix lint
davemarco Dec 28, 2024
0ab6e0e
fix lint
davemarco Dec 28, 2024
d4ed4f6
fix lint
davemarco Dec 28, 2024
82b9802
fix lint?
davemarco Dec 29, 2024
393049b
fix lint?
davemarco Dec 29, 2024
5428403
fix lint
davemarco Dec 29, 2024
7e261f7
fix lint
davemarco Dec 29, 2024
0bd9b27
fix lint
davemarco Dec 29, 2024
d207630
haiqi review
davemarco Jan 13, 2025
c2fd37d
haiqi review
davemarco Jan 13, 2025
cdafb8d
haiqi review
davemarco Jan 16, 2025
dcadf04
haiqi review
davemarco Jan 16, 2025
265b4e4
add initializer for variable
davemarco Jan 16, 2025
c7361c2
attempt to fix lint
davemarco Jan 16, 2025
910e558
saving previous work
davemarco Jan 27, 2025
3ab46fd
merge
davemarco Feb 9, 2025
a12ac42
moving to new metadata, sfav2
davemarco Feb 9, 2025
4c26177
small changes
davemarco Feb 9, 2025
7916bb9
small changes
davemarco Feb 9, 2025
7fc5cb9
latest changes
davemarco Feb 9, 2025
0ae4822
small
davemarco Feb 9, 2025
1b7d73e
small changes
davemarco Feb 9, 2025
7b68544
small changes
davemarco Feb 9, 2025
05377b8
haiqi review
davemarco Feb 10, 2025
e0fcefe
small fix
davemarco Feb 10, 2025
d8a3c70
haiqi review remove offset function
davemarco Feb 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions components/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,9 @@ set(SOURCE_FILES_unitTest
src/clp/streaming_archive/reader/Segment.hpp
src/clp/streaming_archive/reader/SegmentManager.cpp
src/clp/streaming_archive/reader/SegmentManager.hpp
src/clp/streaming_archive/single_file_archive/Defs.hpp
src/clp/streaming_archive/single_file_archive/writer.cpp
src/clp/streaming_archive/single_file_archive/writer.hpp
davemarco marked this conversation as resolved.
Show resolved Hide resolved
src/clp/streaming_archive/writer/Archive.cpp
src/clp/streaming_archive/writer/Archive.hpp
src/clp/streaming_archive/writer/File.cpp
Expand Down
3 changes: 3 additions & 0 deletions components/core/src/clp/clp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ set(
../streaming_archive/reader/Segment.hpp
../streaming_archive/reader/SegmentManager.cpp
../streaming_archive/reader/SegmentManager.hpp
../streaming_archive/single_file_archive/Defs.hpp
../streaming_archive/single_file_archive/writer.cpp
../streaming_archive/single_file_archive/writer.hpp
../streaming_archive/writer/Archive.cpp
../streaming_archive/writer/Archive.hpp
../streaming_archive/writer/File.cpp
Expand Down
4 changes: 4 additions & 0 deletions components/core/src/clp/clp/CommandLineArguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,10 @@ CommandLineArguments::parse_arguments(int argc, char const* argv[]) {
->default_value(m_schema_file_path),
"Path to a schema file. If not specified, heuristics are used to determine "
"dictionary variables. See README-Schema.md for details."
)(
"single-file-archive",
po::bool_switch(&m_single_file_archive),
"Output archive as a single-file archive"
);

po::options_description all_compression_options;
Expand Down
4 changes: 4 additions & 0 deletions components/core/src/clp/clp/CommandLineArguments.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class CommandLineArguments : public CommandLineArgumentsBase {
explicit CommandLineArguments(std::string const& program_name)
: CommandLineArgumentsBase(program_name),
m_show_progress(false),
m_single_file_archive(false),
m_sort_input_files(true),
m_print_archive_stats_progress(false),
m_target_segment_uncompressed_size(1L * 1024 * 1024 * 1024),
Expand All @@ -45,6 +46,8 @@ class CommandLineArguments : public CommandLineArgumentsBase {

bool show_progress() const { return m_show_progress; }

[[nodiscard]] auto single_file_archive() const -> bool { return m_single_file_archive; }

bool sort_input_files() const { return m_sort_input_files; }

bool print_archive_stats_progress() const { return m_print_archive_stats_progress; }
Expand Down Expand Up @@ -92,6 +95,7 @@ class CommandLineArguments : public CommandLineArgumentsBase {
std::string m_output_dir;
std::string m_schema_file_path;
bool m_show_progress;
bool m_single_file_archive;
bool m_print_archive_stats_progress;
size_t m_target_encoded_file_size;
size_t m_target_segment_uncompressed_size;
Expand Down
7 changes: 5 additions & 2 deletions components/core/src/clp/clp/compression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ bool compress(
archive_user_config.global_metadata_db = global_metadata_db.get();
archive_user_config.print_archive_stats_progress
= command_line_args.print_archive_stats_progress();
archive_user_config.use_single_file_archive = command_line_args.single_file_archive();

// Open Archive
streaming_archive::writer::Archive archive_writer;
Expand Down Expand Up @@ -135,7 +136,8 @@ bool compress(
);
}
for (auto it = files_to_compress.cbegin(); it != files_to_compress.cend(); ++it) {
if (archive_writer.get_data_size_of_dictionaries() >= target_data_size_of_dictionaries) {
if (archive_writer.get_data_size_of_dictionaries() >= target_data_size_of_dictionaries)
{
split_archive(archive_user_config, archive_writer);
}
if (false
Expand Down Expand Up @@ -163,7 +165,8 @@ bool compress(
file_group_id_comparator);
// Compress grouped files
for (auto const& file_to_compress : grouped_files_to_compress) {
if (archive_writer.get_data_size_of_dictionaries() >= target_data_size_of_dictionaries) {
if (archive_writer.get_data_size_of_dictionaries() >= target_data_size_of_dictionaries)
{
split_archive(archive_user_config, archive_writer);
}
if (false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#ifndef CLP_STREAMING_ARCHIVE_SINGLE_FILE_ARCHIVE_DEFS_HPP
#define CLP_STREAMING_ARCHIVE_SINGLE_FILE_ARCHIVE_DEFS_HPP

#include <cstdint>
#include <string>

#include "../../Defs.h"
#include "../ArchiveMetadata.hpp"
#include "../Constants.hpp"
#include "msgpack.hpp"

namespace clp::streaming_archive::single_file_archive {

using single_file_archive_format_version_t = uint32_t;

// Single file archive version.
constexpr uint8_t cVersionMajor{0};
constexpr uint8_t cVersionMinor{1};
constexpr uint16_t cVersionPatch{1};
constexpr single_file_archive_format_version_t cVersion{cVersionMajor << 24 | cVersionMinor << 16 | cVersionPatch};

static constexpr size_t cNumMagicNumberChars{4};
static constexpr std::array<uint8_t, cNumMagicNumberChars>
cUnstructuredSfaMagicNumber{'Y', 'C', 'L', 'P'};
static constexpr std::string_view cUnstructuredSfaExtension{".clp"};

static constexpr size_t cNumStaticFiles{6};
constexpr std::array<char const*, cNumStaticFiles> cStaticArchiveFileNames{
cMetadataFileName,
cMetadataDBFileName,
cLogTypeDictFilename,
cLogTypeSegmentIndexFilename,
cVarDictFilename,
cVarSegmentIndexFilename
};

static constexpr size_t cNumUnused{6};

struct __attribute__((packed)) SingleFileArchiveHeader {
std::array<uint8_t, cNumMagicNumberChars> magic;
single_file_archive_format_version_t version;
uint64_t metadata_size;
std::array<uint64_t, cNumUnused> unused;
};

struct FileInfo {
davemarco marked this conversation as resolved.
Show resolved Hide resolved
std::string name;
uint64_t offset;
// Variables are renamed when serialized to match single-file archive specification.
MSGPACK_DEFINE_MAP(MSGPACK_NVP("n", name), MSGPACK_NVP("o", offset));
};

struct SingleFileArchiveMetadata {
std::vector<FileInfo> archive_files;
ArchiveMetadata archive_metadata;
uint64_t num_segments;
MSGPACK_DEFINE_MAP(archive_files, archive_metadata, num_segments);
};
} // namespace clp::streaming_archive::single_file_archive

#endif // CLP_STREAMING_ARCHIVE_SINGLE_FILE_ARCHIVE_DEFS_HPP
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
#include "writer.hpp"

#include <cstddef>
#include <cstring>
#include <filesystem>
#include <sstream>
#include <vector>

#include <fmt/core.h>
#include <msgpack.hpp>
#include <spdlog.h>

#include "../../Defs.h"
#include "../../ErrorCode.hpp"
#include "../../FileReader.hpp"
#include "../../FileWriter.hpp"
#include "../../TraceableException.hpp"
#include "../ArchiveMetadata.hpp"
#include "../Constants.hpp"
#include "Defs.hpp"

namespace clp::streaming_archive::single_file_archive {

namespace {
constexpr size_t cReadBlockSize = 4096;

/**
haiqi96 marked this conversation as resolved.
Show resolved Hide resolved
* Gets the size of a file specified by `file_path` and adds it to file section `offset`.
* @param file_path
* @param[out] offset File section offset for the single-file archive. The returned offset
* represents the starting position of the next file in single-file archive.
* @throws OperationFailed if error getting file size.
*/
auto get_file_size_and_update_offset(std::filesystem::path const& file_path, uint64_t& offset)
-> void;
haiqi96 marked this conversation as resolved.
Show resolved Hide resolved

/**
* Generates metadata for the file section of a single-file archive. The metadata consists
* of a list of file names and their corresponding starting offsets.
*
* @param multi_file_archive_path
* @param next_segment_id
* @return Vector containing a `FileInfo` struct for every file in the multi-file archive.
* @throws Propagates `update_offset`'s exceptions.
davemarco marked this conversation as resolved.
Show resolved Hide resolved
*/
[[nodiscard]] auto
get_file_infos(std::filesystem::path const& multi_file_archive_path, segment_id_t next_segment_id)
davemarco marked this conversation as resolved.
Show resolved Hide resolved
-> std::vector<FileInfo>;

/**
* Combines file section metadata, multi-file archive metadata, and the number of segments into
* single-file archive metadata. Once combined, serializes the metadata into MsgPack format.
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/**
* Combines file section metadata, multi-file archive metadata, and the number of segments into
* single-file archive metadata. Once combined, serializes the metadata into MsgPack format.
*
/**
* Combines file section metadata, multi-file archive metadata, and the number of segments into
* single-file archive metadata and serializes the metadata into MsgPack format.
*

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about. I feel like the second "and" after a list makes the sentence awkward

Combines file section metadata, multi-file archive metadata, and the number of segments into
single-file archive metadata, then serializes the metadata into MsgPack format.

* @param multi_file_archive_metadata
* @param multi_file_archive_path
* @param next_segment_id
* @return Packed metadata.
*/
[[nodiscard]] auto pack_single_file_archive_metadata(
ArchiveMetadata const& multi_file_archive_metadata,
std::filesystem::path const& multi_file_archive_path,
segment_id_t next_segment_id
) -> std::stringstream;

/**
* Writes single-file archive header.
*
* @param single_file_archive_writer
* @param packed_metadata_size
*/
auto write_archive_header(FileWriter& single_file_archive_writer, size_t packed_metadata_size) -> void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Resolve clang-format pipeline failures.

Multiple lines violate the required code style. Please run clang-format or apply the suggested changes to pass the lint checks.

#!/bin/bash
clang-format -i components/core/src/clp/streaming_archive/single_file_archive/writer.cpp

Also applies to: 79-79, 88-88, 91-91, 173-173, 184-184, 189-189

🧰 Tools
🪛 GitHub Actions: clp-lint

[error] 71-71: code should be clang-formatted


/**
* Reads the content of a file and writes it to the single-file archive.
* @param file_path
* @param single_file_archive_writer
* @throws OperationFailed if reading the file fails.
*/
auto write_archive_file(std::string const& file_path, FileWriter& single_file_archive_writer) -> void;

/**
* Iterates over files in the multi-file archive and copies their contents to the single-file archive.
* Skips metadata file, which should be handled by `write_archive_metadata` method.
*
* @param single_file_archive_writer
* @param multi_file_archive_path
* @param next_segment_id
* @throws Propagates `update_offset`'s exceptions.
davemarco marked this conversation as resolved.
Show resolved Hide resolved
*/
auto write_archive_files(
FileWriter& single_file_archive_writer,
std::filesystem::path const& multi_file_archive_path,
segment_id_t next_segment_id
) -> void;

auto get_file_size_and_update_offset(std::filesystem::path const& file_path, uint64_t& offset)
davemarco marked this conversation as resolved.
Show resolved Hide resolved
-> void {
try {
auto size = std::filesystem::file_size(file_path);
offset += size;
davemarco marked this conversation as resolved.
Show resolved Hide resolved
} catch (std::filesystem::filesystem_error const& e) {
throw OperationFailed(
ErrorCode_Failure,
__FILENAME__,
__LINE__,
fmt::format("Failed to get file size: {}", e.what())
);
}
}

auto
get_file_infos(std::filesystem::path const& multi_file_archive_path, segment_id_t next_segment_id)
-> std::vector<FileInfo> {
std::vector<FileInfo> files;
uint64_t offset = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
uint64_t offset = 0;
uint64_t offset{0};


for (auto const& static_archive_file_name : cStaticArchiveFileNames) {
files.emplace_back(FileInfo{std::string(static_archive_file_name), offset});
get_file_size_and_update_offset(multi_file_archive_path / static_archive_file_name, offset);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now looking at the code again, wouldn't it make more sense to:

  • Let get_file_size_and_update_offset only return file_size, i.e. turn it to get_file_size. In this case, maybe we already have similar methods somewhere in shared utils. if not, maybe we can create one as share method instead of defining it only in this file.
  • Let get_file_infos increment the offset.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you feel about removing the function completely? I don't think we have an existing function in utils that calls stat on a closed file.

Something like

offset += std::filesystem::file_size(multi_file_archive_path / static_archive_file_name);

I think I originally created the function, so I could rethrow the filesystem exception as our own exception. But on second thought, I think it's fine to just throw the filesystem exception, and document it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel it is ok. I remember Zhihao had a talk about error handling but I wasn't paying attention enough.

@LinZhihao-723, do you think we can directly throw the exception from std::filesystem ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made change for now

}

std::filesystem::path segment_dir_path = multi_file_archive_path / cSegmentsDirname;

for (size_t i = 0; i < next_segment_id; ++i) {
auto const segment_id = std::to_string(i);
files.emplace_back(FileInfo{segment_id, offset});
get_file_size_and_update_offset(segment_dir_path / segment_id, offset);
}

// Add sentinel indicating total size of all files.
files.emplace_back(FileInfo{"", offset});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

considering defining "" as a constant in defs.hpp?


return files;
}

auto pack_single_file_archive_metadata(
ArchiveMetadata const& multi_file_archive_metadata,
std::filesystem::path const& multi_file_archive_path,
segment_id_t next_segment_id
) -> std::stringstream {
SingleFileArchiveMetadata single_file_archive{
.archive_files = get_file_infos(multi_file_archive_path, next_segment_id),
.archive_metadata = multi_file_archive_metadata,
.num_segments = next_segment_id,
};

std::stringstream buf;
msgpack::pack(buf, single_file_archive);

return buf;
}

auto write_archive_header(FileWriter& single_file_archive_writer, size_t packed_metadata_size) -> void {
SingleFileArchiveHeader header{
.magic = cUnstructuredSfaMagicNumber,
.version = cVersion,
.metadata_size = packed_metadata_size,
.unused{}
};

single_file_archive_writer.write(reinterpret_cast<char const*>(&header), sizeof(header));
}

auto write_archive_file(std::filesystem::path const& file_path, FileWriter& single_file_archive_writer)
-> void {
FileReader reader(file_path.string());
std::array<char, cReadBlockSize> read_buffer{};
while (true) {
size_t num_bytes_read{};
ErrorCode const error_code
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use auto

Suggested change
ErrorCode const error_code
auto const error_code

= reader.try_read(read_buffer.data(), cReadBlockSize, num_bytes_read);
if (ErrorCode_EndOfFile == error_code) {
break;
}
if (ErrorCode_Success != error_code) {
throw OperationFailed(error_code, __FILENAME__, __LINE__);
}
single_file_archive_writer.write(read_buffer.data(), num_bytes_read);
}
}

auto write_archive_files(
FileWriter& single_file_archive_writer,
std::filesystem::path const& multi_file_archive_path,
segment_id_t next_segment_id
) -> void {
for (auto const& static_archive_file_name : cStaticArchiveFileNames) {
std::filesystem::path static_archive_file_path
davemarco marked this conversation as resolved.
Show resolved Hide resolved
= multi_file_archive_path / static_archive_file_name;
write_archive_file(static_archive_file_path, single_file_archive_writer);
}

std::filesystem::path segment_dir_path = multi_file_archive_path / cSegmentsDirname;
for (size_t i = 0; i < next_segment_id; ++i) {
std::filesystem::path segment_path = segment_dir_path / std::to_string(i);
davemarco marked this conversation as resolved.
Show resolved Hide resolved
write_archive_file(segment_path, single_file_archive_writer);
}
}
} // namespace

auto write_single_file_archive(
ArchiveMetadata const& multi_file_archive_metadata,
std::filesystem::path const& multi_file_archive_path,
segment_id_t next_segment_id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about "last_segment_id" as suggested in my previous review.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I missed this. last_segment_id is slightly inaccurate since it is actually an id for a segment that does not exist (it is the next segment to be written). The last_segment_id is the next_segment_id -1.
I think num_segments could also work. Let me know what you think.

) -> void {
FileWriter single_file_archive_writer;
std::filesystem::path single_file_archive_path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

= multi_file_archive_path.string()
+ std::string(single_file_archive::cUnstructuredSfaExtension);

if (std::filesystem::exists(single_file_archive_path)) {
throw OperationFailed(ErrorCode_Failure, __FILENAME__, __LINE__);
}
davemarco marked this conversation as resolved.
Show resolved Hide resolved

single_file_archive_writer.open(
single_file_archive_path.string(),
FileWriter::OpenMode::CREATE_FOR_WRITING
);

auto const packed_metadata = pack_single_file_archive_metadata(
multi_file_archive_metadata,
multi_file_archive_path,
next_segment_id
);

write_archive_header(single_file_archive_writer, packed_metadata.str().size());
write_archive_files(single_file_archive_writer, multi_file_archive_path, next_segment_id);

single_file_archive_writer.close();
try {
std::filesystem::remove_all(multi_file_archive_path);
} catch (std::filesystem::filesystem_error& e) {
throw OperationFailed(ErrorCode_Failure, __FILENAME__, __LINE__);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you try to see if an exception is throw here, what will user see?

There are cases where the exception is caught and rethrown by some upper level caller, and as a result it's really hard to root cause the issue just by looking at the exception text. Want to avoid this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screenshot 2025-02-09 at 4 56 09 PM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exception propagates to the top which is good. If you want i can change the message from single_file_archive operation failed to something custom about multi-file archive not being deleted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kirkrodrigues wonder if we should strictly throw an exception here, or report an warning.
Technically, the singile file archive is correctly created, we just fail to remove mulit-archive files.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't looked at the code, but if the only issue is unnecessary files on disk, sure we could change it to a warning log.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to SPDLOG_WARN

}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling for cleanup operation

  1. The error message is not propagated when file removal fails
  2. Consider verifying if the archive was written successfully before removing the original files
     archive_writer.close();
+    // Verify the archive was written successfully
+    if (!std::filesystem::exists(single_file_archive_path) ||
+        std::filesystem::file_size(single_file_archive_path) == 0) {
+        throw OperationFailed(
+            ErrorCode_Failure,
+            __FILENAME__,
+            __LINE__,
+            "Failed to write single-file archive"
+        );
+    }
     try {
         std::filesystem::remove_all(multi_file_archive_path);
     } catch (std::filesystem::filesystem_error& e) {
-        throw OperationFailed(ErrorCode_Failure, __FILENAME__, __LINE__);
+        throw OperationFailed(
+            ErrorCode_Failure,
+            __FILENAME__,
+            __LINE__,
+            fmt::format("Failed to remove original archive: {}", e.what())
+        );
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
std::filesystem::remove_all(multi_file_archive_path);
} catch (std::filesystem::filesystem_error& e) {
throw OperationFailed(ErrorCode_Failure, __FILENAME__, __LINE__);
}
archive_writer.close();
// Verify the archive was written successfully
if (!std::filesystem::exists(single_file_archive_path) ||
std::filesystem::file_size(single_file_archive_path) == 0) {
throw OperationFailed(
ErrorCode_Failure,
__FILENAME__,
__LINE__,
"Failed to write single-file archive"
);
}
try {
std::filesystem::remove_all(multi_file_archive_path);
} catch (std::filesystem::filesystem_error& e) {
throw OperationFailed(
ErrorCode_Failure,
__FILENAME__,
__LINE__,
fmt::format("Failed to remove original archive: {}", e.what())
);
}

}
} // namespace clp::streaming_archive::single_file_archive
Loading
Loading