From 3dae8069f68bce45a23118afa9e426ffc5913335 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Mon, 14 Oct 2024 20:52:07 -0400 Subject: [PATCH 01/40] Refactor StreamReader to modularize decoding logic. --- CMakeLists.txt | 5 +- src/clp_ffi_js/ir/StreamReader.cpp | 77 +++++++++++--------------- src/clp_ffi_js/ir/StreamReader.hpp | 19 +++++-- src/clp_ffi_js/ir/decoding_methods.cpp | 36 ++++++++++++ src/clp_ffi_js/ir/decoding_methods.hpp | 10 ++++ 5 files changed, 96 insertions(+), 51 deletions(-) create mode 100644 src/clp_ffi_js/ir/decoding_methods.cpp create mode 100644 src/clp_ffi_js/ir/decoding_methods.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 753dee44..80568fe2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,7 +112,10 @@ target_include_directories( target_include_directories(${CLP_FFI_JS_BIN_NAME} PRIVATE src/) -set(CLP_FFI_JS_SRC_MAIN src/clp_ffi_js/ir/StreamReader.cpp) +set(CLP_FFI_JS_SRC_MAIN + src/clp_ffi_js/ir/decoding_methods.cpp + src/clp_ffi_js/ir/StreamReader.cpp +) set(CLP_FFI_JS_SRC_CLP_CORE src/submodules/clp/components/core/src/clp/ffi/ir_stream/decoding_methods.cpp diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index b9c86b6b..a4a01f20 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -27,6 +26,7 @@ #include #include +#include #include #include @@ -48,52 +48,10 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> StreamReader { auto zstd_decompressor{std::make_unique()}; zstd_decompressor->open(data_buffer.data(), length); - bool is_four_bytes_encoding{true}; - if (auto const err{ - clp::ffi::ir_stream::get_encoding_type(*zstd_decompressor, is_four_bytes_encoding) - }; - clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != err) - { - SPDLOG_CRITICAL("Failed to decode encoding type, err={}", err); - throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_MetadataCorrupted, - __FILENAME__, - __LINE__, - "Failed to decode encoding type." - }; - } - if (false == is_four_bytes_encoding) { - throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_Unsupported, - __FILENAME__, - __LINE__, - "IR stream uses unsupported encoding." - }; - } - - auto result{ - clp::ir::LogEventDeserializer::create(*zstd_decompressor) - }; - if (result.has_error()) { - auto const error_code{result.error()}; - SPDLOG_CRITICAL( - "Failed to create deserializer: {}:{}", - error_code.category().name(), - error_code.message() - ); - throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_Failure, - __FILENAME__, - __LINE__, - "Failed to create deserializer" - }; - } - - StreamReaderDataContext stream_reader_data_context{ - std::move(data_buffer), + auto stream_reader_data_context{create_deserializer_and_data_context( std::move(zstd_decompressor), - std::move(result.value()) - }; + std::move(data_buffer) + )}; return StreamReader{std::move(stream_reader_data_context)}; } @@ -251,6 +209,33 @@ StreamReader::StreamReader( std::move(stream_reader_data_context) )}, m_ts_pattern{m_stream_reader_data_context->get_deserializer().get_timestamp_pattern()} {} + +auto StreamReader::create_deserializer_and_data_context( + std::unique_ptr&& zstd_decompressor, + clp::Array&& data_buffer +) -> StreamReaderDataContext { + rewind_reader_and_verify_encoding_type(*zstd_decompressor); + + auto result{ + clp::ir::LogEventDeserializer::create(*zstd_decompressor) + }; + if (result.has_error()) { + auto const error_code{result.error()}; + SPDLOG_CRITICAL( + "Failed to create deserializer: {}:{}", + error_code.category().name(), + error_code.message() + ); + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_Failure, + __FILENAME__, + __LINE__, + "Failed to create deserializer" + }; + } + + return {std::move(data_buffer), std::move(zstd_decompressor), std::move(result.value())}; +} } // namespace clp_ffi_js::ir namespace { diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index dec6c360..50fecb4c 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -1,9 +1,11 @@ #ifndef CLP_FFI_JS_IR_STREAM_READER_HPP #define CLP_FFI_JS_IR_STREAM_READER_HPP +#include #include #include #include +#include #include #include @@ -14,6 +16,8 @@ #include #include +using clp::ir::four_byte_encoded_variable_t; + namespace clp_ffi_js::ir { EMSCRIPTEN_DECLARE_VAL_TYPE(DataArrayTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(DecodedResultsTsType); @@ -97,12 +101,19 @@ class StreamReader { private: // Constructor - explicit StreamReader(StreamReaderDataContext&& - stream_reader_data_context); + explicit StreamReader( + StreamReaderDataContext&& stream_reader_data_context + ); + + // Methods + [[nodiscard]] static auto create_deserializer_and_data_context( + std::unique_ptr&& zstd_decompressor, + clp::Array&& data_buffer + ) -> StreamReaderDataContext; // Variables - std::vector> m_encoded_log_events; - std::unique_ptr> + std::vector> m_encoded_log_events; + std::unique_ptr> m_stream_reader_data_context; FilteredLogEventsMap m_filtered_log_event_map; clp::TimestampPattern m_ts_pattern; diff --git a/src/clp_ffi_js/ir/decoding_methods.cpp b/src/clp_ffi_js/ir/decoding_methods.cpp new file mode 100644 index 00000000..4d59bf55 --- /dev/null +++ b/src/clp_ffi_js/ir/decoding_methods.cpp @@ -0,0 +1,36 @@ +#include "decoding_methods.hpp" + +#include +#include +#include +#include +#include + +#include + +namespace clp_ffi_js::ir { +auto rewind_reader_and_verify_encoding_type(clp::ReaderInterface& reader) -> void { + reader.seek_from_begin(0); + + bool is_four_bytes_encoding{true}; + if (auto const err{clp::ffi::ir_stream::get_encoding_type(reader, is_four_bytes_encoding)}; + clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != err) + { + SPDLOG_CRITICAL("Failed to decode encoding type, err={}", err); + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_MetadataCorrupted, + __FILENAME__, + __LINE__, + "Failed to decode encoding type." + }; + } + if (false == is_four_bytes_encoding) { + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_Unsupported, + __FILENAME__, + __LINE__, + "IR stream uses unsupported encoding." + }; + } +} +} // namespace clp_ffi_js::ir diff --git a/src/clp_ffi_js/ir/decoding_methods.hpp b/src/clp_ffi_js/ir/decoding_methods.hpp new file mode 100644 index 00000000..9e24280d --- /dev/null +++ b/src/clp_ffi_js/ir/decoding_methods.hpp @@ -0,0 +1,10 @@ +#ifndef CLP_FFI_JS_IR_DECODING_METHODS_HPP +#define CLP_FFI_JS_IR_DECODING_METHODS_HPP + +#include + +namespace clp_ffi_js::ir { +auto rewind_reader_and_verify_encoding_type(clp::ReaderInterface& reader) -> void; +} // namespace clp_ffi_js::ir + +#endif // CLP_FFI_JS_IR_DECODING_METHODS_HPP From ab32045c2cdada8a4c2f0b64bb58c998afdb41a3 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Mon, 14 Oct 2024 20:59:17 -0400 Subject: [PATCH 02/40] Add a comment section for methods in StreamReader.hpp. --- src/clp_ffi_js/ir/StreamReader.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index 50fecb4c..8cc84469 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -56,6 +56,7 @@ class StreamReader { // Delete move assignment operator since it's also disabled in `clp::ir::LogEventDeserializer`. auto operator=(StreamReader&&) -> StreamReader& = delete; + // Methods /** * @return The number of events buffered. */ From 8dc3dff0290ad1edac822f3e18410ddc453ce8c6 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Mon, 14 Oct 2024 21:10:29 -0400 Subject: [PATCH 03/40] Add `get_version` to decoding methods. --- src/clp_ffi_js/ir/decoding_methods.cpp | 45 ++++++++++++++++++++++++++ src/clp_ffi_js/ir/decoding_methods.hpp | 3 ++ 2 files changed, 48 insertions(+) diff --git a/src/clp_ffi_js/ir/decoding_methods.cpp b/src/clp_ffi_js/ir/decoding_methods.cpp index 4d59bf55..81063f6a 100644 --- a/src/clp_ffi_js/ir/decoding_methods.cpp +++ b/src/clp_ffi_js/ir/decoding_methods.cpp @@ -1,14 +1,59 @@ #include "decoding_methods.hpp" +#include +#include +#include +#include +#include + #include #include +#include #include #include +#include #include #include namespace clp_ffi_js::ir { +auto get_version(clp::ReaderInterface& reader) -> std::string { + // The encoding type bytes must be consumed before the metadata can be read. + rewind_reader_and_verify_encoding_type(reader); + + // Deserialize metadata bytes from preamble. + clp::ffi::ir_stream::encoded_tag_t metadata_type{}; + std::vector metadata_bytes; + auto const deserialize_preamble_result{ + clp::ffi::ir_stream::deserialize_preamble(reader, metadata_type, metadata_bytes) + }; + if (clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != deserialize_preamble_result) { + SPDLOG_CRITICAL( + "Failed to deserialize preamble for version reading: {}", + deserialize_preamble_result + ); + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_Failure, + __FILENAME__, + __LINE__, + "Failed to deserialize preamble for version reading." + }; + } + + // Deserialize metadata bytes which is encoded in JSON. + std::string_view const metadata_view{ + clp::size_checked_pointer_cast(metadata_bytes.data()), + metadata_bytes.size() + }; + nlohmann::json const metadata = nlohmann::json::parse(metadata_view); + + // Retrieve version from metadata. + auto const& version{metadata.at(clp::ffi::ir_stream::cProtocol::Metadata::VersionKey)}; + SPDLOG_INFO("The version is {}", version); + + return version; +} + auto rewind_reader_and_verify_encoding_type(clp::ReaderInterface& reader) -> void { reader.seek_from_begin(0); diff --git a/src/clp_ffi_js/ir/decoding_methods.hpp b/src/clp_ffi_js/ir/decoding_methods.hpp index 9e24280d..6791fd21 100644 --- a/src/clp_ffi_js/ir/decoding_methods.hpp +++ b/src/clp_ffi_js/ir/decoding_methods.hpp @@ -1,9 +1,12 @@ #ifndef CLP_FFI_JS_IR_DECODING_METHODS_HPP #define CLP_FFI_JS_IR_DECODING_METHODS_HPP +#include + #include namespace clp_ffi_js::ir { +auto get_version(clp::ReaderInterface& reader) -> std::string; auto rewind_reader_and_verify_encoding_type(clp::ReaderInterface& reader) -> void; } // namespace clp_ffi_js::ir From eba1d30c7a3e7e73f7668f59a5a82ac99b945bb7 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Mon, 14 Oct 2024 21:12:50 -0400 Subject: [PATCH 04/40] Move `#include ` from StreamReader.hpp to StreamReader.cpp. --- src/clp_ffi_js/ir/StreamReader.cpp | 1 + src/clp_ffi_js/ir/StreamReader.hpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index a4a01f20..86224f88 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index 8cc84469..a370bbc6 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -10,7 +10,6 @@ #include #include -#include #include #include From 5398d1d403b84cb5af579b289d8cfb68adb688d4 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Mon, 14 Oct 2024 21:16:08 -0400 Subject: [PATCH 05/40] Rename StreamReader -> IRStreamReader. --- CMakeLists.txt | 2 +- .../{StreamReader.cpp => IRStreamReader.cpp} | 36 +++++++++---------- .../{StreamReader.hpp => IRStreamReader.hpp} | 24 ++++++------- src/clp_ffi_js/ir/StreamReaderDataContext.hpp | 2 +- 4 files changed, 32 insertions(+), 32 deletions(-) rename src/clp_ffi_js/ir/{StreamReader.cpp => IRStreamReader.cpp} (86%) rename src/clp_ffi_js/ir/{StreamReader.hpp => IRStreamReader.hpp} (87%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 80568fe2..86473c50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,7 +114,7 @@ target_include_directories(${CLP_FFI_JS_BIN_NAME} PRIVATE src/) set(CLP_FFI_JS_SRC_MAIN src/clp_ffi_js/ir/decoding_methods.cpp - src/clp_ffi_js/ir/StreamReader.cpp + src/clp_ffi_js/ir/IRStreamReader.cpp ) set(CLP_FFI_JS_SRC_CLP_CORE diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/IRStreamReader.cpp similarity index 86% rename from src/clp_ffi_js/ir/StreamReader.cpp rename to src/clp_ffi_js/ir/IRStreamReader.cpp index 86224f88..d6c561f7 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/IRStreamReader.cpp @@ -1,4 +1,4 @@ -#include "StreamReader.hpp" +#include "IRStreamReader.hpp" #include #include @@ -35,9 +35,9 @@ using namespace std::literals::string_literals; using clp::ir::four_byte_encoded_variable_t; namespace clp_ffi_js::ir { -auto StreamReader::create(DataArrayTsType const& data_array) -> StreamReader { +auto IRStreamReader::create(DataArrayTsType const& data_array) -> IRStreamReader { auto const length{data_array["length"].as()}; - SPDLOG_INFO("StreamReader::create: got buffer of length={}", length); + SPDLOG_INFO("IRStreamReader::create: got buffer of length={}", length); // Copy array from JavaScript to C++ clp::Array data_buffer{length}; @@ -53,14 +53,14 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> StreamReader { std::move(zstd_decompressor), std::move(data_buffer) )}; - return StreamReader{std::move(stream_reader_data_context)}; + return IRStreamReader{std::move(stream_reader_data_context)}; } -auto StreamReader::get_num_events_buffered() const -> size_t { +auto IRStreamReader::get_num_events_buffered() const -> size_t { return m_encoded_log_events.size(); } -auto StreamReader::get_filtered_log_event_map() const -> FilteredLogEventMapTsType { +auto IRStreamReader::get_filtered_log_event_map() const -> FilteredLogEventMapTsType { if (false == m_filtered_log_event_map.has_value()) { return FilteredLogEventMapTsType{emscripten::val::null()}; } @@ -68,7 +68,7 @@ auto StreamReader::get_filtered_log_event_map() const -> FilteredLogEventMapTsTy return FilteredLogEventMapTsType{emscripten::val::array(m_filtered_log_event_map.value())}; } -void StreamReader::filter_log_events(emscripten::val const& log_level_filter) { +void IRStreamReader::filter_log_events(emscripten::val const& log_level_filter) { if (log_level_filter.isNull()) { m_filtered_log_event_map.reset(); return; @@ -90,7 +90,7 @@ void StreamReader::filter_log_events(emscripten::val const& log_level_filter) { } } -auto StreamReader::deserialize_stream() -> size_t { +auto IRStreamReader::deserialize_stream() -> size_t { if (nullptr == m_stream_reader_data_context) { return m_encoded_log_events.size(); } @@ -150,7 +150,7 @@ auto StreamReader::deserialize_stream() -> size_t { return m_encoded_log_events.size(); } -auto StreamReader::decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const +auto IRStreamReader::decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const -> DecodedResultsTsType { if (use_filter && false == m_filtered_log_event_map.has_value()) { return DecodedResultsTsType{emscripten::val::null()}; @@ -202,7 +202,7 @@ auto StreamReader::decode_range(size_t begin_idx, size_t end_idx, bool use_filte return DecodedResultsTsType(results); } -StreamReader::StreamReader( +IRStreamReader::IRStreamReader( StreamReaderDataContext&& stream_reader_data_context ) : m_stream_reader_data_context{std::make_unique< @@ -211,7 +211,7 @@ StreamReader::StreamReader( )}, m_ts_pattern{m_stream_reader_data_context->get_deserializer().get_timestamp_pattern()} {} -auto StreamReader::create_deserializer_and_data_context( +auto IRStreamReader::create_deserializer_and_data_context( std::unique_ptr&& zstd_decompressor, clp::Array&& data_buffer ) -> StreamReaderDataContext { @@ -247,21 +247,21 @@ EMSCRIPTEN_BINDINGS(ClpIrStreamReader) { ); emscripten::register_type("number[] | null"); - emscripten::class_("ClpIrStreamReader") + emscripten::class_("ClpIrStreamReader") .constructor( - &clp_ffi_js::ir::StreamReader::create, + &clp_ffi_js::ir::IRStreamReader::create, emscripten::return_value_policy::take_ownership() ) .function( "getNumEventsBuffered", - &clp_ffi_js::ir::StreamReader::get_num_events_buffered + &clp_ffi_js::ir::IRStreamReader::get_num_events_buffered ) .function( "getFilteredLogEventMap", - &clp_ffi_js::ir::StreamReader::get_filtered_log_event_map + &clp_ffi_js::ir::IRStreamReader::get_filtered_log_event_map ) - .function("filterLogEvents", &clp_ffi_js::ir::StreamReader::filter_log_events) - .function("deserializeStream", &clp_ffi_js::ir::StreamReader::deserialize_stream) - .function("decodeRange", &clp_ffi_js::ir::StreamReader::decode_range); + .function("filterLogEvents", &clp_ffi_js::ir::IRStreamReader::filter_log_events) + .function("deserializeStream", &clp_ffi_js::ir::IRStreamReader::deserialize_stream) + .function("decodeRange", &clp_ffi_js::ir::IRStreamReader::decode_range); } } // namespace diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/IRStreamReader.hpp similarity index 87% rename from src/clp_ffi_js/ir/StreamReader.hpp rename to src/clp_ffi_js/ir/IRStreamReader.hpp index a370bbc6..db267afa 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/IRStreamReader.hpp @@ -1,5 +1,5 @@ -#ifndef CLP_FFI_JS_IR_STREAM_READER_HPP -#define CLP_FFI_JS_IR_STREAM_READER_HPP +#ifndef CLP_FFI_JS_IR_IR_STREAM_READER_HPP +#define CLP_FFI_JS_IR_IR_STREAM_READER_HPP #include #include @@ -26,7 +26,7 @@ EMSCRIPTEN_DECLARE_VAL_TYPE(FilteredLogEventMapTsType); * Class to deserialize and decode Zstandard-compressed CLP IR streams as well as format decoded * log events. */ -class StreamReader { +class IRStreamReader { public: /** * Mapping between an index in the filtered log events collection to an index in the unfiltered @@ -35,25 +35,25 @@ class StreamReader { using FilteredLogEventsMap = std::optional>; /** - * Creates a StreamReader to read from the given array. + * Creates a IRStreamReader to read from the given array. * * @param data_array An array containing a Zstandard-compressed IR stream. * @return The created instance. * @throw ClpFfiJsException if any error occurs. */ - [[nodiscard]] static auto create(DataArrayTsType const& data_array) -> StreamReader; + [[nodiscard]] static auto create(DataArrayTsType const& data_array) -> IRStreamReader; // Destructor - ~StreamReader() = default; + ~IRStreamReader() = default; // Disable copy constructor and assignment operator - StreamReader(StreamReader const&) = delete; - auto operator=(StreamReader const&) -> StreamReader& = delete; + IRStreamReader(IRStreamReader const&) = delete; + auto operator=(IRStreamReader const&) -> IRStreamReader& = delete; // Define default move constructor - StreamReader(StreamReader&&) = default; + IRStreamReader(IRStreamReader&&) = default; // Delete move assignment operator since it's also disabled in `clp::ir::LogEventDeserializer`. - auto operator=(StreamReader&&) -> StreamReader& = delete; + auto operator=(IRStreamReader&&) -> IRStreamReader& = delete; // Methods /** @@ -101,7 +101,7 @@ class StreamReader { private: // Constructor - explicit StreamReader( + explicit IRStreamReader( StreamReaderDataContext&& stream_reader_data_context ); @@ -120,4 +120,4 @@ class StreamReader { }; } // namespace clp_ffi_js::ir -#endif // CLP_FFI_JS_IR_STREAM_READER_HPP +#endif // CLP_FFI_JS_IR_IR_STREAM_READER_HPP diff --git a/src/clp_ffi_js/ir/StreamReaderDataContext.hpp b/src/clp_ffi_js/ir/StreamReaderDataContext.hpp index 091b0b05..c6f8134c 100644 --- a/src/clp_ffi_js/ir/StreamReaderDataContext.hpp +++ b/src/clp_ffi_js/ir/StreamReaderDataContext.hpp @@ -11,7 +11,7 @@ namespace clp_ffi_js::ir { /** - * The data context for a `StreamReader`. It encapsulates a chain of the following resources: + * The data context for a `IRStreamReader`. It encapsulates a chain of the following resources: * A `clp::ir::LogEventDeserializer` that reads from a * `clp::streaming_compression::zstd::Decompressor`, which in turn reads from a `clp::Array`. * @tparam encoded_variable_t Type of encoded variables encoded in the stream. From cfd55ca2af9b456eeacef1acfffabe93722e5134 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Mon, 14 Oct 2024 21:18:18 -0400 Subject: [PATCH 06/40] Rename ClpIrStreamReader to ClpIRStreamReader in bindings. --- src/clp_ffi_js/ir/IRStreamReader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clp_ffi_js/ir/IRStreamReader.cpp b/src/clp_ffi_js/ir/IRStreamReader.cpp index d6c561f7..e48b7310 100644 --- a/src/clp_ffi_js/ir/IRStreamReader.cpp +++ b/src/clp_ffi_js/ir/IRStreamReader.cpp @@ -240,14 +240,14 @@ auto IRStreamReader::create_deserializer_and_data_context( } // namespace clp_ffi_js::ir namespace { -EMSCRIPTEN_BINDINGS(ClpIrStreamReader) { +EMSCRIPTEN_BINDINGS(ClpIRStreamReader) { emscripten::register_type("Uint8Array"); emscripten::register_type( "Array<[string, number, number, number]>" ); emscripten::register_type("number[] | null"); - emscripten::class_("ClpIrStreamReader") + emscripten::class_("ClpIRStreamReader") .constructor( &clp_ffi_js::ir::IRStreamReader::create, emscripten::return_value_policy::take_ownership() From d1ed2f02fc739e065d5ff8fcd1de3994dba3f01b Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Mon, 14 Oct 2024 21:24:07 -0400 Subject: [PATCH 07/40] Extract a StreamReader base class from IRStreamReader. --- CMakeLists.txt | 1 + src/clp_ffi_js/ir/IRStreamReader.cpp | 11 ++-- src/clp_ffi_js/ir/IRStreamReader.hpp | 23 ++++--- src/clp_ffi_js/ir/StreamReader.cpp | 70 ++++++++++++++++++++++ src/clp_ffi_js/ir/StreamReader.hpp | 89 ++++++++++++++++++++++++++++ 5 files changed, 175 insertions(+), 19 deletions(-) create mode 100644 src/clp_ffi_js/ir/StreamReader.cpp create mode 100644 src/clp_ffi_js/ir/StreamReader.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 86473c50..4f3b8c6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,6 +115,7 @@ target_include_directories(${CLP_FFI_JS_BIN_NAME} PRIVATE src/) set(CLP_FFI_JS_SRC_MAIN src/clp_ffi_js/ir/decoding_methods.cpp src/clp_ffi_js/ir/IRStreamReader.cpp + src/clp_ffi_js/ir/StreamReader.cpp ) set(CLP_FFI_JS_SRC_CLP_CORE diff --git a/src/clp_ffi_js/ir/IRStreamReader.cpp b/src/clp_ffi_js/ir/IRStreamReader.cpp index e48b7310..ecab8a79 100644 --- a/src/clp_ffi_js/ir/IRStreamReader.cpp +++ b/src/clp_ffi_js/ir/IRStreamReader.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include using namespace std::literals::string_literals; @@ -241,13 +242,9 @@ auto IRStreamReader::create_deserializer_and_data_context( namespace { EMSCRIPTEN_BINDINGS(ClpIRStreamReader) { - emscripten::register_type("Uint8Array"); - emscripten::register_type( - "Array<[string, number, number, number]>" - ); - emscripten::register_type("number[] | null"); - - emscripten::class_("ClpIRStreamReader") + emscripten::class_< + clp_ffi_js::ir::IRStreamReader, + emscripten::base>("ClpIRStreamReader") .constructor( &clp_ffi_js::ir::IRStreamReader::create, emscripten::return_value_policy::take_ownership() diff --git a/src/clp_ffi_js/ir/IRStreamReader.hpp b/src/clp_ffi_js/ir/IRStreamReader.hpp index db267afa..137a2996 100644 --- a/src/clp_ffi_js/ir/IRStreamReader.hpp +++ b/src/clp_ffi_js/ir/IRStreamReader.hpp @@ -13,20 +13,19 @@ #include #include +#include #include using clp::ir::four_byte_encoded_variable_t; namespace clp_ffi_js::ir { -EMSCRIPTEN_DECLARE_VAL_TYPE(DataArrayTsType); -EMSCRIPTEN_DECLARE_VAL_TYPE(DecodedResultsTsType); -EMSCRIPTEN_DECLARE_VAL_TYPE(FilteredLogEventMapTsType); - /** * Class to deserialize and decode Zstandard-compressed CLP IR streams as well as format decoded * log events. */ -class IRStreamReader { +class IRStreamReader : public StreamReader { + friend StreamReader; + public: /** * Mapping between an index in the filtered log events collection to an index in the unfiltered @@ -44,7 +43,7 @@ class IRStreamReader { [[nodiscard]] static auto create(DataArrayTsType const& data_array) -> IRStreamReader; // Destructor - ~IRStreamReader() = default; + ~IRStreamReader() override = default; // Disable copy constructor and assignment operator IRStreamReader(IRStreamReader const&) = delete; @@ -59,19 +58,19 @@ class IRStreamReader { /** * @return The number of events buffered. */ - [[nodiscard]] auto get_num_events_buffered() const -> size_t; + [[nodiscard]] auto get_num_events_buffered() const -> size_t override; /** * @return The filtered log events map. */ - [[nodiscard]] auto get_filtered_log_event_map() const -> FilteredLogEventMapTsType; + [[nodiscard]] auto get_filtered_log_event_map() const -> FilteredLogEventMapTsType override; /** * Generates a filtered collection from all log events. * * @param log_level_filter Array of selected log levels */ - void filter_log_events(emscripten::val const& log_level_filter); + void filter_log_events(emscripten::val const& log_level_filter) override; /** * Deserializes all log events in the stream. After the stream has been exhausted, it will be @@ -79,7 +78,7 @@ class IRStreamReader { * * @return The number of successfully deserialized ("valid") log events. */ - [[nodiscard]] auto deserialize_stream() -> size_t; + [[nodiscard]] auto deserialize_stream() -> size_t override; /** * Decodes log events in the range `[beginIdx, endIdx)` of the filtered or unfiltered @@ -96,8 +95,8 @@ class IRStreamReader { * @return null if any log event in the range doesn't exist (e.g. the range exceeds the number * of log events in the collection). */ - [[nodiscard]] auto - decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const -> DecodedResultsTsType; + [[nodiscard]] auto decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const + -> DecodedResultsTsType override; private: // Constructor diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp new file mode 100644 index 00000000..6906d7e0 --- /dev/null +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -0,0 +1,70 @@ +#include "StreamReader.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace clp_ffi_js::ir { +auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr { + auto const length{data_array["length"].as()}; + SPDLOG_INFO("KVPairIRStreamReader::create: got buffer of length={}", length); + + // Copy array from JavaScript to C++ + clp::Array data_buffer{length}; + // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) + emscripten::val::module_property("HEAPU8") + .call("set", data_array, reinterpret_cast(data_buffer.data())); + // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) + + auto zstd_decompressor{std::make_unique()}; + zstd_decompressor->open(data_buffer.data(), length); + + auto const version{get_version(*zstd_decompressor)}; + if (version == "v0.0.0") { + auto stream_reader_data_context{IRStreamReader::create_deserializer_and_data_context( + std::move(zstd_decompressor), + std::move(data_buffer) + )}; + + return std::unique_ptr( + new IRStreamReader(std::move(stream_reader_data_context)) + ); + } + + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_Unsupported, + __FILENAME__, + __LINE__, + std::format("Unable to create stream reader for IR data with version {}.", version) + }; +} +} // namespace clp_ffi_js::ir + +namespace { +EMSCRIPTEN_BINDINGS(ClpStreamReader) { + emscripten::register_type("Uint8Array"); + emscripten::register_type( + "Array<[string, number, number, number]>" + ); + emscripten::register_type("number[] | null"); + + emscripten::class_("ClpStreamReader") + .constructor( + &clp_ffi_js::ir::StreamReader::create, + emscripten::return_value_policy::take_ownership() + ); +} +} // namespace diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp new file mode 100644 index 00000000..ad9cbaa0 --- /dev/null +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -0,0 +1,89 @@ +#ifndef CLP_FFI_JS_IR_STREAM_READER_HPP +#define CLP_FFI_JS_IR_STREAM_READER_HPP + +#include +#include + +#include + +namespace clp_ffi_js::ir { +EMSCRIPTEN_DECLARE_VAL_TYPE(DataArrayTsType); +EMSCRIPTEN_DECLARE_VAL_TYPE(DecodedResultsTsType); +EMSCRIPTEN_DECLARE_VAL_TYPE(FilteredLogEventMapTsType); + +/** + * Class to deserialize and decode Zstandard-compressed CLP IR streams as well as format decoded + * log events. + */ +class StreamReader { +public: + /** + * Creates a StreamReader to read from the given array. + * + * @param data_array An array containing a Zstandard-compressed IR stream. + * @return The created instance. + * @throw ClpFfiJsException if any error occurs. + */ + [[nodiscard]] static auto create(DataArrayTsType const& data_array + ) -> std::unique_ptr; + + // Destructor + virtual ~StreamReader() = default; + + // Disable copy constructor and assignment operator + StreamReader(StreamReader const&) = delete; + auto operator=(StreamReader const&) -> StreamReader& = delete; + + // Define default move constructor + StreamReader(StreamReader&&) = default; + // Delete move assignment operator since it's also disabled in `clp::ir::LogEventDeserializer`. + auto operator=(StreamReader&&) -> StreamReader& = delete; + + /** + * @return The number of events buffered. + */ + [[nodiscard]] virtual auto get_num_events_buffered() const -> size_t = 0; + + /** + * @return The filtered log events map. + */ + [[nodiscard]] virtual auto get_filtered_log_event_map() const -> FilteredLogEventMapTsType = 0; + + /** + * Generates a filtered collection from all log events. + * + * @param log_level_filter Array of selected log levels + */ + virtual void filter_log_events(emscripten::val const& log_level_filter) = 0; + + /** + * Deserializes all log events in the stream. After the stream has been exhausted, it will be + * deallocated. + * + * @return The number of successfully deserialized ("valid") log events. + */ + [[nodiscard]] virtual auto deserialize_stream() -> size_t = 0; + + /** + * Decodes log events in the range `[beginIdx, endIdx)` of the filtered or unfiltered + * (depending on the value of `useFilter`) log events collection. + * + * @param begin_idx + * @param end_idx + * @param use_filter Whether to decode from the filtered or unfiltered log events collection. + * @return An array where each element is a decoded log event represented by an array of: + * - The log event's message + * - The log event's timestamp as milliseconds since the Unix epoch + * - The log event's log level as an integer that indexes into `cLogLevelNames` + * - The log event's number (1-indexed) in the stream + * @return null if any log event in the range doesn't exist (e.g. the range exceeds the number + * of log events in the collection). + */ + [[nodiscard]] virtual auto decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const + -> DecodedResultsTsType = 0; + +protected: + explicit StreamReader() = default; +}; +} // namespace clp_ffi_js::ir +#endif // CLP_FFI_JS_IR_STREAM_READER_HPP From bf5e4c9563bc6a2c25de5514161b997ab396b1a9 Mon Sep 17 00:00:00 2001 From: Junhao Liao Date: Mon, 14 Oct 2024 21:37:44 -0400 Subject: [PATCH 08/40] Rename IRStreamReader -> IrStreamReader. --- CMakeLists.txt | 2 +- ...{IRStreamReader.cpp => IrStreamReader.cpp} | 40 +++++++++---------- ...{IRStreamReader.hpp => IrStreamReader.hpp} | 18 ++++----- src/clp_ffi_js/ir/StreamReader.cpp | 8 ++-- src/clp_ffi_js/ir/StreamReaderDataContext.hpp | 2 +- 5 files changed, 35 insertions(+), 35 deletions(-) rename src/clp_ffi_js/ir/{IRStreamReader.cpp => IrStreamReader.cpp} (88%) rename src/clp_ffi_js/ir/{IRStreamReader.hpp => IrStreamReader.hpp} (90%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f3b8c6f..2d584386 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,7 +114,7 @@ target_include_directories(${CLP_FFI_JS_BIN_NAME} PRIVATE src/) set(CLP_FFI_JS_SRC_MAIN src/clp_ffi_js/ir/decoding_methods.cpp - src/clp_ffi_js/ir/IRStreamReader.cpp + src/clp_ffi_js/ir/IrStreamReader.cpp src/clp_ffi_js/ir/StreamReader.cpp ) diff --git a/src/clp_ffi_js/ir/IRStreamReader.cpp b/src/clp_ffi_js/ir/IrStreamReader.cpp similarity index 88% rename from src/clp_ffi_js/ir/IRStreamReader.cpp rename to src/clp_ffi_js/ir/IrStreamReader.cpp index ecab8a79..8ec58c2e 100644 --- a/src/clp_ffi_js/ir/IRStreamReader.cpp +++ b/src/clp_ffi_js/ir/IrStreamReader.cpp @@ -1,4 +1,4 @@ -#include "IRStreamReader.hpp" +#include "IrStreamReader.hpp" #include #include @@ -36,9 +36,9 @@ using namespace std::literals::string_literals; using clp::ir::four_byte_encoded_variable_t; namespace clp_ffi_js::ir { -auto IRStreamReader::create(DataArrayTsType const& data_array) -> IRStreamReader { +auto IrStreamReader::create(DataArrayTsType const& data_array) -> IrStreamReader { auto const length{data_array["length"].as()}; - SPDLOG_INFO("IRStreamReader::create: got buffer of length={}", length); + SPDLOG_INFO("IrStreamReader::create: got buffer of length={}", length); // Copy array from JavaScript to C++ clp::Array data_buffer{length}; @@ -54,14 +54,14 @@ auto IRStreamReader::create(DataArrayTsType const& data_array) -> IRStreamReader std::move(zstd_decompressor), std::move(data_buffer) )}; - return IRStreamReader{std::move(stream_reader_data_context)}; + return IrStreamReader{std::move(stream_reader_data_context)}; } -auto IRStreamReader::get_num_events_buffered() const -> size_t { +auto IrStreamReader::get_num_events_buffered() const -> size_t { return m_encoded_log_events.size(); } -auto IRStreamReader::get_filtered_log_event_map() const -> FilteredLogEventMapTsType { +auto IrStreamReader::get_filtered_log_event_map() const -> FilteredLogEventMapTsType { if (false == m_filtered_log_event_map.has_value()) { return FilteredLogEventMapTsType{emscripten::val::null()}; } @@ -69,7 +69,7 @@ auto IRStreamReader::get_filtered_log_event_map() const -> FilteredLogEventMapTs return FilteredLogEventMapTsType{emscripten::val::array(m_filtered_log_event_map.value())}; } -void IRStreamReader::filter_log_events(emscripten::val const& log_level_filter) { +void IrStreamReader::filter_log_events(emscripten::val const& log_level_filter) { if (log_level_filter.isNull()) { m_filtered_log_event_map.reset(); return; @@ -91,7 +91,7 @@ void IRStreamReader::filter_log_events(emscripten::val const& log_level_filter) } } -auto IRStreamReader::deserialize_stream() -> size_t { +auto IrStreamReader::deserialize_stream() -> size_t { if (nullptr == m_stream_reader_data_context) { return m_encoded_log_events.size(); } @@ -151,7 +151,7 @@ auto IRStreamReader::deserialize_stream() -> size_t { return m_encoded_log_events.size(); } -auto IRStreamReader::decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const +auto IrStreamReader::decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const -> DecodedResultsTsType { if (use_filter && false == m_filtered_log_event_map.has_value()) { return DecodedResultsTsType{emscripten::val::null()}; @@ -203,7 +203,7 @@ auto IRStreamReader::decode_range(size_t begin_idx, size_t end_idx, bool use_fil return DecodedResultsTsType(results); } -IRStreamReader::IRStreamReader( +IrStreamReader::IrStreamReader( StreamReaderDataContext&& stream_reader_data_context ) : m_stream_reader_data_context{std::make_unique< @@ -212,7 +212,7 @@ IRStreamReader::IRStreamReader( )}, m_ts_pattern{m_stream_reader_data_context->get_deserializer().get_timestamp_pattern()} {} -auto IRStreamReader::create_deserializer_and_data_context( +auto IrStreamReader::create_deserializer_and_data_context( std::unique_ptr&& zstd_decompressor, clp::Array&& data_buffer ) -> StreamReaderDataContext { @@ -241,24 +241,24 @@ auto IRStreamReader::create_deserializer_and_data_context( } // namespace clp_ffi_js::ir namespace { -EMSCRIPTEN_BINDINGS(ClpIRStreamReader) { +EMSCRIPTEN_BINDINGS(ClpIrStreamReader) { emscripten::class_< - clp_ffi_js::ir::IRStreamReader, - emscripten::base>("ClpIRStreamReader") + clp_ffi_js::ir::IrStreamReader, + emscripten::base>("ClpIrStreamReader") .constructor( - &clp_ffi_js::ir::IRStreamReader::create, + &clp_ffi_js::ir::IrStreamReader::create, emscripten::return_value_policy::take_ownership() ) .function( "getNumEventsBuffered", - &clp_ffi_js::ir::IRStreamReader::get_num_events_buffered + &clp_ffi_js::ir::IrStreamReader::get_num_events_buffered ) .function( "getFilteredLogEventMap", - &clp_ffi_js::ir::IRStreamReader::get_filtered_log_event_map + &clp_ffi_js::ir::IrStreamReader::get_filtered_log_event_map ) - .function("filterLogEvents", &clp_ffi_js::ir::IRStreamReader::filter_log_events) - .function("deserializeStream", &clp_ffi_js::ir::IRStreamReader::deserialize_stream) - .function("decodeRange", &clp_ffi_js::ir::IRStreamReader::decode_range); + .function("filterLogEvents", &clp_ffi_js::ir::IrStreamReader::filter_log_events) + .function("deserializeStream", &clp_ffi_js::ir::IrStreamReader::deserialize_stream) + .function("decodeRange", &clp_ffi_js::ir::IrStreamReader::decode_range); } } // namespace diff --git a/src/clp_ffi_js/ir/IRStreamReader.hpp b/src/clp_ffi_js/ir/IrStreamReader.hpp similarity index 90% rename from src/clp_ffi_js/ir/IRStreamReader.hpp rename to src/clp_ffi_js/ir/IrStreamReader.hpp index 137a2996..768742c6 100644 --- a/src/clp_ffi_js/ir/IRStreamReader.hpp +++ b/src/clp_ffi_js/ir/IrStreamReader.hpp @@ -23,7 +23,7 @@ namespace clp_ffi_js::ir { * Class to deserialize and decode Zstandard-compressed CLP IR streams as well as format decoded * log events. */ -class IRStreamReader : public StreamReader { +class IrStreamReader : public StreamReader { friend StreamReader; public: @@ -34,25 +34,25 @@ class IRStreamReader : public StreamReader { using FilteredLogEventsMap = std::optional>; /** - * Creates a IRStreamReader to read from the given array. + * Creates a IrStreamReader to read from the given array. * * @param data_array An array containing a Zstandard-compressed IR stream. * @return The created instance. * @throw ClpFfiJsException if any error occurs. */ - [[nodiscard]] static auto create(DataArrayTsType const& data_array) -> IRStreamReader; + [[nodiscard]] static auto create(DataArrayTsType const& data_array) -> IrStreamReader; // Destructor - ~IRStreamReader() override = default; + ~IrStreamReader() override = default; // Disable copy constructor and assignment operator - IRStreamReader(IRStreamReader const&) = delete; - auto operator=(IRStreamReader const&) -> IRStreamReader& = delete; + IrStreamReader(IrStreamReader const&) = delete; + auto operator=(IrStreamReader const&) -> IrStreamReader& = delete; // Define default move constructor - IRStreamReader(IRStreamReader&&) = default; + IrStreamReader(IrStreamReader&&) = default; // Delete move assignment operator since it's also disabled in `clp::ir::LogEventDeserializer`. - auto operator=(IRStreamReader&&) -> IRStreamReader& = delete; + auto operator=(IrStreamReader&&) -> IrStreamReader& = delete; // Methods /** @@ -100,7 +100,7 @@ class IRStreamReader : public StreamReader { private: // Constructor - explicit IRStreamReader( + explicit IrStreamReader( StreamReaderDataContext&& stream_reader_data_context ); diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index 6906d7e0..176af4d3 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -15,7 +15,7 @@ #include #include -#include +#include namespace clp_ffi_js::ir { auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr { @@ -34,13 +34,13 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< auto const version{get_version(*zstd_decompressor)}; if (version == "v0.0.0") { - auto stream_reader_data_context{IRStreamReader::create_deserializer_and_data_context( + auto stream_reader_data_context{IrStreamReader::create_deserializer_and_data_context( std::move(zstd_decompressor), std::move(data_buffer) )}; - return std::unique_ptr( - new IRStreamReader(std::move(stream_reader_data_context)) + return std::unique_ptr( + new IrStreamReader(std::move(stream_reader_data_context)) ); } diff --git a/src/clp_ffi_js/ir/StreamReaderDataContext.hpp b/src/clp_ffi_js/ir/StreamReaderDataContext.hpp index c6f8134c..651f741f 100644 --- a/src/clp_ffi_js/ir/StreamReaderDataContext.hpp +++ b/src/clp_ffi_js/ir/StreamReaderDataContext.hpp @@ -11,7 +11,7 @@ namespace clp_ffi_js::ir { /** - * The data context for a `IRStreamReader`. It encapsulates a chain of the following resources: + * The data context for a `IrStreamReader`. It encapsulates a chain of the following resources: * A `clp::ir::LogEventDeserializer` that reads from a * `clp::streaming_compression::zstd::Decompressor`, which in turn reads from a `clp::Array`. * @tparam encoded_variable_t Type of encoded variables encoded in the stream. From c474bb42564e44f9708f502a2424660878081618 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Fri, 1 Nov 2024 15:08:51 +0000 Subject: [PATCH 09/40] some restructure --- src/clp_ffi_js/ir/IrStreamReader.cpp | 49 +--------------------- src/clp_ffi_js/ir/IrStreamReader.hpp | 27 +++++-------- src/clp_ffi_js/ir/StreamReader.cpp | 16 ++++++-- src/clp_ffi_js/ir/decoding_methods.cpp | 56 ++++++++++++++------------ src/clp_ffi_js/ir/decoding_methods.hpp | 2 +- 5 files changed, 56 insertions(+), 94 deletions(-) diff --git a/src/clp_ffi_js/ir/IrStreamReader.cpp b/src/clp_ffi_js/ir/IrStreamReader.cpp index 3140eac0..f9200576 100644 --- a/src/clp_ffi_js/ir/IrStreamReader.cpp +++ b/src/clp_ffi_js/ir/IrStreamReader.cpp @@ -32,30 +32,10 @@ #include #include -using namespace std::literals::string_literals; -using clp::ir::four_byte_encoded_variable_t; - namespace clp_ffi_js::ir { -auto IrStreamReader::create(DataArrayTsType const& data_array) -> IrStreamReader { - auto const length{data_array["length"].as()}; - SPDLOG_INFO("IrStreamReader::create: got buffer of length={}", length); - - // Copy array from JavaScript to C++ - clp::Array data_buffer{length}; - // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) - emscripten::val::module_property("HEAPU8") - .call("set", data_array, reinterpret_cast(data_buffer.data())); - // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) - auto zstd_decompressor{std::make_unique()}; - zstd_decompressor->open(data_buffer.data(), length); - - auto stream_reader_data_context{create_deserializer_and_data_context( - std::move(zstd_decompressor), - std::move(data_buffer) - )}; - return IrStreamReader{std::move(stream_reader_data_context)}; -} +using namespace std::literals::string_literals; +using clp::ir::four_byte_encoded_variable_t; auto IrStreamReader::get_num_events_buffered() const -> size_t { return m_encoded_log_events.size(); @@ -216,8 +196,6 @@ auto IrStreamReader::create_data_context( std::unique_ptr&& zstd_decompressor, clp::Array&& data_buffer ) -> StreamReaderDataContext { - rewind_reader_and_validate_encoding_type(*zstd_decompressor); - auto result{ clp::ir::LogEventDeserializer::create(*zstd_decompressor) }; @@ -239,26 +217,3 @@ auto IrStreamReader::create_data_context( return {std::move(data_buffer), std::move(zstd_decompressor), std::move(result.value())}; } } // namespace clp_ffi_js::ir - -namespace { -EMSCRIPTEN_BINDINGS(ClpIrStreamReader) { - emscripten::class_< - clp_ffi_js::ir::IrStreamReader, - emscripten::base>("ClpIrStreamReader") - .constructor( - &clp_ffi_js::ir::IrStreamReader::create, - emscripten::return_value_policy::take_ownership() - ) - .function( - "getNumEventsBuffered", - &clp_ffi_js::ir::IrStreamReader::get_num_events_buffered - ) - .function( - "getFilteredLogEventMap", - &clp_ffi_js::ir::IrStreamReader::get_filtered_log_event_map - ) - .function("filterLogEvents", &clp_ffi_js::ir::IrStreamReader::filter_log_events) - .function("deserializeStream", &clp_ffi_js::ir::IrStreamReader::deserialize_stream) - .function("decodeRange", &clp_ffi_js::ir::IrStreamReader::decode_range); -} -} // namespace diff --git a/src/clp_ffi_js/ir/IrStreamReader.hpp b/src/clp_ffi_js/ir/IrStreamReader.hpp index 768742c6..db83621f 100644 --- a/src/clp_ffi_js/ir/IrStreamReader.hpp +++ b/src/clp_ffi_js/ir/IrStreamReader.hpp @@ -16,32 +16,23 @@ #include #include +namespace clp_ffi_js::ir { using clp::ir::four_byte_encoded_variable_t; -namespace clp_ffi_js::ir { /** - * Class to deserialize and decode Zstandard-compressed CLP IR streams as well as format decoded + * Mapping between an index in the filtered log events collection to an index in the unfiltered + * log events collection. + */ +using FilteredLogEventsMap = std::optional>; + +/** + * Class to deserialize and decode Zstandard-compressed CLP IRv1 streams as well as format decoded * log events. */ class IrStreamReader : public StreamReader { friend StreamReader; public: - /** - * Mapping between an index in the filtered log events collection to an index in the unfiltered - * log events collection. - */ - using FilteredLogEventsMap = std::optional>; - - /** - * Creates a IrStreamReader to read from the given array. - * - * @param data_array An array containing a Zstandard-compressed IR stream. - * @return The created instance. - * @throw ClpFfiJsException if any error occurs. - */ - [[nodiscard]] static auto create(DataArrayTsType const& data_array) -> IrStreamReader; - // Destructor ~IrStreamReader() override = default; @@ -105,7 +96,7 @@ class IrStreamReader : public StreamReader { ); // Methods - [[nodiscard]] static auto create_deserializer_and_data_context( + [[nodiscard]] static auto create_data_context( std::unique_ptr&& zstd_decompressor, clp::Array&& data_buffer ) -> StreamReaderDataContext; diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index d2280a34..a7db473c 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -20,7 +20,7 @@ namespace clp_ffi_js::ir { auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr { auto const length{data_array["length"].as()}; - SPDLOG_INFO("KVPairIRStreamReader::create: got buffer of length={}", length); + SPDLOG_INFO("StreamReader::create: got buffer of length={}", length); // Copy array from JavaScript to C++ clp::Array data_buffer{length}; @@ -60,11 +60,21 @@ EMSCRIPTEN_BINDINGS(ClpStreamReader) { "Array<[string, number, number, number]>" ); emscripten::register_type("number[] | null"); - emscripten::class_("ClpStreamReader") .constructor( &clp_ffi_js::ir::StreamReader::create, emscripten::return_value_policy::take_ownership() - ); + ) + .function( + "getNumEventsBuffered", + &clp_ffi_js::ir::StreamReader::get_num_events_buffered + ) + .function( + "getFilteredLogEventMap", + &clp_ffi_js::ir::StreamReader::get_filtered_log_event_map + ) + .function("filterLogEvents", &clp_ffi_js::ir::StreamReader::filter_log_events) + .function("deserializeStream", &clp_ffi_js::ir::StreamReader::deserialize_stream) + .function("decodeRange", &clp_ffi_js::ir::StreamReader::decode_range); } } // namespace diff --git a/src/clp_ffi_js/ir/decoding_methods.cpp b/src/clp_ffi_js/ir/decoding_methods.cpp index 3c420ecb..86bee1de 100644 --- a/src/clp_ffi_js/ir/decoding_methods.cpp +++ b/src/clp_ffi_js/ir/decoding_methods.cpp @@ -17,6 +17,37 @@ #include namespace clp_ffi_js::ir { +/** + * Rewinds the reader to the beginning and validates the CLP IR data encoding type. + * @param reader + * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is + * unsupported. + */ +static auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void { + reader.seek_from_begin(0); + + bool is_four_bytes_encoding{true}; + if (auto const err{clp::ffi::ir_stream::get_encoding_type(reader, is_four_bytes_encoding)}; + clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != err) + { + SPDLOG_CRITICAL("Failed to decode encoding type, err={}", err); + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_MetadataCorrupted, + __FILENAME__, + __LINE__, + "Failed to decode encoding type." + }; + } + if (false == is_four_bytes_encoding) { + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_Unsupported, + __FILENAME__, + __LINE__, + "IR stream uses unsupported encoding." + }; + } +} + auto get_version(clp::ReaderInterface& reader) -> std::string { // The encoding type bytes must be consumed before the metadata can be read. rewind_reader_and_validate_encoding_type(reader); @@ -53,29 +84,4 @@ auto get_version(clp::ReaderInterface& reader) -> std::string { return version; } - -auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void { - reader.seek_from_begin(0); - - bool is_four_bytes_encoding{true}; - if (auto const err{clp::ffi::ir_stream::get_encoding_type(reader, is_four_bytes_encoding)}; - clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != err) - { - SPDLOG_CRITICAL("Failed to decode encoding type, err={}", err); - throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_MetadataCorrupted, - __FILENAME__, - __LINE__, - "Failed to decode encoding type." - }; - } - if (false == is_four_bytes_encoding) { - throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_Unsupported, - __FILENAME__, - __LINE__, - "IR stream uses unsupported encoding." - }; - } -} } // namespace clp_ffi_js::ir diff --git a/src/clp_ffi_js/ir/decoding_methods.hpp b/src/clp_ffi_js/ir/decoding_methods.hpp index ec3e529b..e743c273 100644 --- a/src/clp_ffi_js/ir/decoding_methods.hpp +++ b/src/clp_ffi_js/ir/decoding_methods.hpp @@ -13,7 +13,7 @@ auto get_version(clp::ReaderInterface& reader) -> std::string; * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is * unsupported. */ -auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void; +static auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void; } // namespace clp_ffi_js::ir #endif // CLP_FFI_JS_IR_DECODING_METHODS_HPP From f4a6896be958598f05bd3c726c64a80850d91308 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Fri, 1 Nov 2024 16:40:08 +0000 Subject: [PATCH 10/40] fix cmake --- CMakeLists.txt | 1 + src/clp_ffi_js/ir/IrStreamReader.cpp | 2 -- src/clp_ffi_js/ir/IrStreamReader.hpp | 1 + src/clp_ffi_js/ir/StreamReader.hpp | 2 -- src/clp_ffi_js/ir/decoding_methods.cpp | 2 +- 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 80568fe2..2d584386 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,6 +114,7 @@ target_include_directories(${CLP_FFI_JS_BIN_NAME} PRIVATE src/) set(CLP_FFI_JS_SRC_MAIN src/clp_ffi_js/ir/decoding_methods.cpp + src/clp_ffi_js/ir/IrStreamReader.cpp src/clp_ffi_js/ir/StreamReader.cpp ) diff --git a/src/clp_ffi_js/ir/IrStreamReader.cpp b/src/clp_ffi_js/ir/IrStreamReader.cpp index f9200576..1b5188bb 100644 --- a/src/clp_ffi_js/ir/IrStreamReader.cpp +++ b/src/clp_ffi_js/ir/IrStreamReader.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -27,7 +26,6 @@ #include #include -#include #include #include #include diff --git a/src/clp_ffi_js/ir/IrStreamReader.hpp b/src/clp_ffi_js/ir/IrStreamReader.hpp index db83621f..72af0c97 100644 --- a/src/clp_ffi_js/ir/IrStreamReader.hpp +++ b/src/clp_ffi_js/ir/IrStreamReader.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index c74c9032..af05323b 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -1,14 +1,12 @@ #ifndef CLP_FFI_JS_IR_STREAM_READER_HPP #define CLP_FFI_JS_IR_STREAM_READER_HPP -#include #include #include #include namespace clp_ffi_js::ir { -using clp::ir::four_byte_encoded_variable_t; EMSCRIPTEN_DECLARE_VAL_TYPE(DataArrayTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(DecodedResultsTsType); diff --git a/src/clp_ffi_js/ir/decoding_methods.cpp b/src/clp_ffi_js/ir/decoding_methods.cpp index 86bee1de..0f8611d7 100644 --- a/src/clp_ffi_js/ir/decoding_methods.cpp +++ b/src/clp_ffi_js/ir/decoding_methods.cpp @@ -23,7 +23,7 @@ namespace clp_ffi_js::ir { * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is * unsupported. */ -static auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void { +auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void { reader.seek_from_begin(0); bool is_four_bytes_encoding{true}; From dba39103000e12fc761b2994f3c244e648b40420 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Fri, 1 Nov 2024 17:51:09 +0000 Subject: [PATCH 11/40] more changes after test --- src/clp_ffi_js/ir/IrStreamReader.cpp | 2 ++ src/clp_ffi_js/ir/IrStreamReader.hpp | 1 - src/clp_ffi_js/ir/StreamReader.cpp | 5 +++-- src/clp_ffi_js/ir/decoding_methods.cpp | 6 ------ src/clp_ffi_js/ir/decoding_methods.hpp | 9 ++++++++- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/clp_ffi_js/ir/IrStreamReader.cpp b/src/clp_ffi_js/ir/IrStreamReader.cpp index 1b5188bb..793cb856 100644 --- a/src/clp_ffi_js/ir/IrStreamReader.cpp +++ b/src/clp_ffi_js/ir/IrStreamReader.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -194,6 +195,7 @@ auto IrStreamReader::create_data_context( std::unique_ptr&& zstd_decompressor, clp::Array&& data_buffer ) -> StreamReaderDataContext { + rewind_reader_and_validate_encoding_type(*zstd_decompressor); auto result{ clp::ir::LogEventDeserializer::create(*zstd_decompressor) }; diff --git a/src/clp_ffi_js/ir/IrStreamReader.hpp b/src/clp_ffi_js/ir/IrStreamReader.hpp index 72af0c97..db83621f 100644 --- a/src/clp_ffi_js/ir/IrStreamReader.hpp +++ b/src/clp_ffi_js/ir/IrStreamReader.hpp @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index a7db473c..452e75ec 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -22,7 +22,7 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< auto const length{data_array["length"].as()}; SPDLOG_INFO("StreamReader::create: got buffer of length={}", length); - // Copy array from JavaScript to C++ + // Copy array from JavaScript to C++. clp::Array data_buffer{length}; // NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast) emscripten::val::module_property("HEAPU8") @@ -33,7 +33,7 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< zstd_decompressor->open(data_buffer.data(), length); auto const version{get_version(*zstd_decompressor)}; - if (version == "v0.0.0") { + if (version == "v0.0.1" || version == "v0.0.0" || version == "0.0.1" || version == "0.0.0") { auto stream_reader_data_context{IrStreamReader::create_data_context( std::move(zstd_decompressor), std::move(data_buffer) @@ -43,6 +43,7 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< new IrStreamReader(std::move(stream_reader_data_context)) ); } + SPDLOG_CRITICAL("Unable to create stream reader for IR data with version {}.", version); throw ClpFfiJsException{ clp::ErrorCode::ErrorCode_Unsupported, diff --git a/src/clp_ffi_js/ir/decoding_methods.cpp b/src/clp_ffi_js/ir/decoding_methods.cpp index 0f8611d7..e3242c86 100644 --- a/src/clp_ffi_js/ir/decoding_methods.cpp +++ b/src/clp_ffi_js/ir/decoding_methods.cpp @@ -17,12 +17,6 @@ #include namespace clp_ffi_js::ir { -/** - * Rewinds the reader to the beginning and validates the CLP IR data encoding type. - * @param reader - * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is - * unsupported. - */ auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void { reader.seek_from_begin(0); diff --git a/src/clp_ffi_js/ir/decoding_methods.hpp b/src/clp_ffi_js/ir/decoding_methods.hpp index e743c273..d6be607f 100644 --- a/src/clp_ffi_js/ir/decoding_methods.hpp +++ b/src/clp_ffi_js/ir/decoding_methods.hpp @@ -6,6 +6,13 @@ #include namespace clp_ffi_js::ir { +/** + * Gets the version of the IR stream. + * @param reader + * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is + * unsupported. + * @throws ClpFfiJsException if the preamble could not be deserialized. + */ auto get_version(clp::ReaderInterface& reader) -> std::string; /** * Rewinds the reader to the beginning and validates the CLP IR data encoding type. @@ -13,7 +20,7 @@ auto get_version(clp::ReaderInterface& reader) -> std::string; * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is * unsupported. */ -static auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void; +auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void; } // namespace clp_ffi_js::ir #endif // CLP_FFI_JS_IR_DECODING_METHODS_HPP From 9ddd97478d321789b6d448ebf4c58ec7f5e3e1c4 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Mon, 4 Nov 2024 21:03:48 +0000 Subject: [PATCH 12/40] junhao changes --- src/clp_ffi_js/ir/IrStreamReader.cpp | 7 ++++++- src/clp_ffi_js/ir/IrStreamReader.hpp | 2 +- src/clp_ffi_js/ir/StreamReader.cpp | 4 ++-- src/clp_ffi_js/ir/StreamReaderDataContext.hpp | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/clp_ffi_js/ir/IrStreamReader.cpp b/src/clp_ffi_js/ir/IrStreamReader.cpp index 793cb856..93c94e83 100644 --- a/src/clp_ffi_js/ir/IrStreamReader.cpp +++ b/src/clp_ffi_js/ir/IrStreamReader.cpp @@ -163,7 +163,12 @@ auto IrStreamReader::decode_range(size_t begin_idx, size_t end_idx, bool use_fil auto const parsed{log_event.get_message().decode_and_unparse()}; if (false == parsed.has_value()) { SPDLOG_ERROR("Failed to decode message."); - break; + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_Failure, + __FILENAME__, + __LINE__, + "Failed to decode message" + }; } message = parsed.value(); diff --git a/src/clp_ffi_js/ir/IrStreamReader.hpp b/src/clp_ffi_js/ir/IrStreamReader.hpp index db83621f..d280a619 100644 --- a/src/clp_ffi_js/ir/IrStreamReader.hpp +++ b/src/clp_ffi_js/ir/IrStreamReader.hpp @@ -91,7 +91,7 @@ class IrStreamReader : public StreamReader { private: // Constructor - explicit IrStreamReader( + IrStreamReader( StreamReaderDataContext&& stream_reader_data_context ); diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index 452e75ec..286b9cd2 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -2,12 +2,12 @@ #include #include -#include #include #include #include #include +#include #include #include #include @@ -43,7 +43,7 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< new IrStreamReader(std::move(stream_reader_data_context)) ); } - SPDLOG_CRITICAL("Unable to create stream reader for IR data with version {}.", version); + SPDLOG_CRITICAL("Unable to create reader for CLP stream with version {}.", version); throw ClpFfiJsException{ clp::ErrorCode::ErrorCode_Unsupported, diff --git a/src/clp_ffi_js/ir/StreamReaderDataContext.hpp b/src/clp_ffi_js/ir/StreamReaderDataContext.hpp index 651f741f..091b0b05 100644 --- a/src/clp_ffi_js/ir/StreamReaderDataContext.hpp +++ b/src/clp_ffi_js/ir/StreamReaderDataContext.hpp @@ -11,7 +11,7 @@ namespace clp_ffi_js::ir { /** - * The data context for a `IrStreamReader`. It encapsulates a chain of the following resources: + * The data context for a `StreamReader`. It encapsulates a chain of the following resources: * A `clp::ir::LogEventDeserializer` that reads from a * `clp::streaming_compression::zstd::Decompressor`, which in turn reads from a `clp::Array`. * @tparam encoded_variable_t Type of encoded variables encoded in the stream. From a5cb52906036098f14762bc198fc824c7bc44654 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Mon, 4 Nov 2024 21:13:46 +0000 Subject: [PATCH 13/40] fix lint --- src/clp_ffi_js/ir/IrStreamReader.cpp | 2 +- src/submodules/clp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clp_ffi_js/ir/IrStreamReader.cpp b/src/clp_ffi_js/ir/IrStreamReader.cpp index 93c94e83..145574d3 100644 --- a/src/clp_ffi_js/ir/IrStreamReader.cpp +++ b/src/clp_ffi_js/ir/IrStreamReader.cpp @@ -167,7 +167,7 @@ auto IrStreamReader::decode_range(size_t begin_idx, size_t end_idx, bool use_fil clp::ErrorCode::ErrorCode_Failure, __FILENAME__, __LINE__, - "Failed to decode message" + "Failed to decode message" }; } message = parsed.value(); diff --git a/src/submodules/clp b/src/submodules/clp index 86299ca2..9f6a6ced 160000 --- a/src/submodules/clp +++ b/src/submodules/clp @@ -1 +1 @@ -Subproject commit 86299ca2907565e09cb10c2ddd3661ad1ceb6cb0 +Subproject commit 9f6a6ced4da504f6ba3c131efa26fd5b30c6f533 From cd50c9a0c762dc9e988b0f0f42e5194cfdcb92eb Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Mon, 4 Nov 2024 21:48:59 +0000 Subject: [PATCH 14/40] version methodology change + better error handling --- src/clp_ffi_js/ir/StreamReader.cpp | 3 ++- src/clp_ffi_js/ir/StreamReader.hpp | 5 +++++ src/clp_ffi_js/ir/decoding_methods.cpp | 19 ++++++++++++++----- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index 286b9cd2..a7d8a239 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -33,7 +33,8 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< zstd_decompressor->open(data_buffer.data(), length); auto const version{get_version(*zstd_decompressor)}; - if (version == "v0.0.1" || version == "v0.0.0" || version == "0.0.1" || version == "0.0.0") { + + if (std::ranges::find(cIrV1Versions, version) != cIrV1Versions.end()) { auto stream_reader_data_context{IrStreamReader::create_data_context( std::move(zstd_decompressor), std::move(data_buffer) diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index af05323b..eda16d56 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -2,6 +2,7 @@ #define CLP_FFI_JS_IR_STREAM_READER_HPP #include +#include #include #include @@ -12,6 +13,10 @@ EMSCRIPTEN_DECLARE_VAL_TYPE(DataArrayTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(DecodedResultsTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(FilteredLogEventMapTsType); +constexpr std::array cIrV1Versions = { + "v0.0.1", "v0.0.0", "0.0.1", "0.0.0" +}; + /** * Class to deserialize and decode Zstandard-compressed CLP IR streams as well as format decoded * log events. diff --git a/src/clp_ffi_js/ir/decoding_methods.cpp b/src/clp_ffi_js/ir/decoding_methods.cpp index e3242c86..aae2731b 100644 --- a/src/clp_ffi_js/ir/decoding_methods.cpp +++ b/src/clp_ffi_js/ir/decoding_methods.cpp @@ -61,7 +61,7 @@ auto get_version(clp::ReaderInterface& reader) -> std::string { clp::ErrorCode::ErrorCode_Failure, __FILENAME__, __LINE__, - "Failed to deserialize preamble for version reading." + fmt::format("Failed to deserialize preamble version reading: {}", deserialize_preamble_result) }; } @@ -70,12 +70,21 @@ auto get_version(clp::ReaderInterface& reader) -> std::string { clp::size_checked_pointer_cast(metadata_bytes.data()), metadata_bytes.size() }; - nlohmann::json const metadata = nlohmann::json::parse(metadata_view); - // Retrieve version from metadata. - auto const& version{metadata.at(clp::ffi::ir_stream::cProtocol::Metadata::VersionKey)}; - SPDLOG_INFO("The version is {}", version); + std::string version; + try { + nlohmann::json const metadata = nlohmann::json::parse(metadata_view); + version = metadata.at(clp::ffi::ir_stream::cProtocol::Metadata::VersionKey); + } catch (const nlohmann::json::exception& e) { + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_MetadataCorrupted, + __FILENAME__, + __LINE__, + fmt::format("Error parsing stream metadata: {}", e.what()) + }; + } + SPDLOG_INFO("The version is {}", version); return version; } } // namespace clp_ffi_js::ir From d2cf12229ad1ab9b1c71981d7e1bd528a3e7fb29 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Mon, 4 Nov 2024 22:36:45 +0000 Subject: [PATCH 15/40] lint fix --- src/clp_ffi_js/ir/StreamReader.cpp | 1 + src/clp_ffi_js/ir/StreamReader.hpp | 7 +++---- src/clp_ffi_js/ir/decoding_methods.cpp | 21 ++++++++++----------- src/clp_ffi_js/ir/decoding_methods.hpp | 1 + 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index a7d8a239..7c957585 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -1,5 +1,6 @@ #include "StreamReader.hpp" +#include #include #include #include diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index eda16d56..b0d6e671 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -1,9 +1,10 @@ #ifndef CLP_FFI_JS_IR_STREAM_READER_HPP #define CLP_FFI_JS_IR_STREAM_READER_HPP +#include #include -#include #include +#include #include @@ -13,9 +14,7 @@ EMSCRIPTEN_DECLARE_VAL_TYPE(DataArrayTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(DecodedResultsTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(FilteredLogEventMapTsType); -constexpr std::array cIrV1Versions = { - "v0.0.1", "v0.0.0", "0.0.1", "0.0.0" -}; +constexpr std::array cIrV1Versions = {"v0.0.1", "v0.0.0", "0.0.1", "0.0.0"}; /** * Class to deserialize and decode Zstandard-compressed CLP IR streams as well as format decoded diff --git a/src/clp_ffi_js/ir/decoding_methods.cpp b/src/clp_ffi_js/ir/decoding_methods.cpp index aae2731b..21a14a6f 100644 --- a/src/clp_ffi_js/ir/decoding_methods.cpp +++ b/src/clp_ffi_js/ir/decoding_methods.cpp @@ -1,6 +1,7 @@ #include "decoding_methods.hpp" #include +#include #include #include #include @@ -53,15 +54,13 @@ auto get_version(clp::ReaderInterface& reader) -> std::string { clp::ffi::ir_stream::deserialize_preamble(reader, metadata_type, metadata_bytes) }; if (clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != deserialize_preamble_result) { - SPDLOG_CRITICAL( - "Failed to deserialize preamble for version reading: {}", - deserialize_preamble_result - ); + SPDLOG_CRITICAL("Failed to deserialize preamble for version reading"); + throw ClpFfiJsException{ clp::ErrorCode::ErrorCode_Failure, __FILENAME__, __LINE__, - fmt::format("Failed to deserialize preamble version reading: {}", deserialize_preamble_result) + "Failed to deserialize preamble for version reading" }; } @@ -75,13 +74,13 @@ auto get_version(clp::ReaderInterface& reader) -> std::string { try { nlohmann::json const metadata = nlohmann::json::parse(metadata_view); version = metadata.at(clp::ffi::ir_stream::cProtocol::Metadata::VersionKey); - } catch (const nlohmann::json::exception& e) { + } catch (nlohmann::json::exception const& e) { throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_MetadataCorrupted, - __FILENAME__, - __LINE__, - fmt::format("Error parsing stream metadata: {}", e.what()) - }; + clp::ErrorCode::ErrorCode_MetadataCorrupted, + __FILENAME__, + __LINE__, + std::format("Error parsing stream metadata: {}", e.what()) + }; } SPDLOG_INFO("The version is {}", version); diff --git a/src/clp_ffi_js/ir/decoding_methods.hpp b/src/clp_ffi_js/ir/decoding_methods.hpp index d6be607f..4fd2a095 100644 --- a/src/clp_ffi_js/ir/decoding_methods.hpp +++ b/src/clp_ffi_js/ir/decoding_methods.hpp @@ -12,6 +12,7 @@ namespace clp_ffi_js::ir { * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is * unsupported. * @throws ClpFfiJsException if the preamble could not be deserialized. + * @return Stream version. */ auto get_version(clp::ReaderInterface& reader) -> std::string; /** From 7fe3a58202f77245d59512866f81910ca3806be5 Mon Sep 17 00:00:00 2001 From: davemarco <83603688+davemarco@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:38:46 -0500 Subject: [PATCH 16/40] Update src/clp_ffi_js/ir/decoding_methods.hpp Co-authored-by: Junhao Liao --- src/clp_ffi_js/ir/decoding_methods.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clp_ffi_js/ir/decoding_methods.hpp b/src/clp_ffi_js/ir/decoding_methods.hpp index 4fd2a095..d80989f4 100644 --- a/src/clp_ffi_js/ir/decoding_methods.hpp +++ b/src/clp_ffi_js/ir/decoding_methods.hpp @@ -7,7 +7,7 @@ namespace clp_ffi_js::ir { /** - * Gets the version of the IR stream. + * Gets the version of the IR stream from the specified reader. * @param reader * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is * unsupported. From 9b67be9b4af1f130b3959435ec21d631b695d93a Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Tue, 5 Nov 2024 15:57:22 +0000 Subject: [PATCH 17/40] fix print statement --- src/clp_ffi_js/ir/decoding_methods.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clp_ffi_js/ir/decoding_methods.cpp b/src/clp_ffi_js/ir/decoding_methods.cpp index 21a14a6f..99e1cecb 100644 --- a/src/clp_ffi_js/ir/decoding_methods.cpp +++ b/src/clp_ffi_js/ir/decoding_methods.cpp @@ -54,13 +54,13 @@ auto get_version(clp::ReaderInterface& reader) -> std::string { clp::ffi::ir_stream::deserialize_preamble(reader, metadata_type, metadata_bytes) }; if (clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != deserialize_preamble_result) { - SPDLOG_CRITICAL("Failed to deserialize preamble for version reading"); + SPDLOG_CRITICAL("Failed to deserialize preamble for version reading: {}", clp::enum_to_underlying_type(deserialize_preamble_result)); throw ClpFfiJsException{ clp::ErrorCode::ErrorCode_Failure, __FILENAME__, __LINE__, - "Failed to deserialize preamble for version reading" + std::format("Failed to deserialize preamble for version reading: {}", clp::enum_to_underlying_type(deserialize_preamble_result)) }; } From fb2b290d21302beb30f6ed349cec9d477550116e Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Tue, 5 Nov 2024 15:58:17 +0000 Subject: [PATCH 18/40] fix lint --- src/clp_ffi_js/ir/decoding_methods.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/clp_ffi_js/ir/decoding_methods.cpp b/src/clp_ffi_js/ir/decoding_methods.cpp index 99e1cecb..eb282fbe 100644 --- a/src/clp_ffi_js/ir/decoding_methods.cpp +++ b/src/clp_ffi_js/ir/decoding_methods.cpp @@ -54,13 +54,19 @@ auto get_version(clp::ReaderInterface& reader) -> std::string { clp::ffi::ir_stream::deserialize_preamble(reader, metadata_type, metadata_bytes) }; if (clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != deserialize_preamble_result) { - SPDLOG_CRITICAL("Failed to deserialize preamble for version reading: {}", clp::enum_to_underlying_type(deserialize_preamble_result)); + SPDLOG_CRITICAL( + "Failed to deserialize preamble for version reading: {}", + clp::enum_to_underlying_type(deserialize_preamble_result) + ); throw ClpFfiJsException{ clp::ErrorCode::ErrorCode_Failure, __FILENAME__, __LINE__, - std::format("Failed to deserialize preamble for version reading: {}", clp::enum_to_underlying_type(deserialize_preamble_result)) + std::format( + "Failed to deserialize preamble for version reading: {}", + clp::enum_to_underlying_type(deserialize_preamble_result) + ) }; } From 464cf3198497ba25428f96695982af6d174c6189 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Tue, 5 Nov 2024 21:25:40 +0000 Subject: [PATCH 19/40] forgot one comment, adding type for log level filter --- src/clp_ffi_js/ir/IrStreamReader.cpp | 2 +- src/clp_ffi_js/ir/IrStreamReader.hpp | 2 +- src/clp_ffi_js/ir/StreamReader.cpp | 3 +++ src/clp_ffi_js/ir/StreamReader.hpp | 3 ++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/clp_ffi_js/ir/IrStreamReader.cpp b/src/clp_ffi_js/ir/IrStreamReader.cpp index 145574d3..381e4144 100644 --- a/src/clp_ffi_js/ir/IrStreamReader.cpp +++ b/src/clp_ffi_js/ir/IrStreamReader.cpp @@ -48,7 +48,7 @@ auto IrStreamReader::get_filtered_log_event_map() const -> FilteredLogEventMapTs return FilteredLogEventMapTsType{emscripten::val::array(m_filtered_log_event_map.value())}; } -void IrStreamReader::filter_log_events(emscripten::val const& log_level_filter) { +void IrStreamReader::filter_log_events(LogLevelFilterTsType const& log_level_filter) { if (log_level_filter.isNull()) { m_filtered_log_event_map.reset(); return; diff --git a/src/clp_ffi_js/ir/IrStreamReader.hpp b/src/clp_ffi_js/ir/IrStreamReader.hpp index d280a619..ba649747 100644 --- a/src/clp_ffi_js/ir/IrStreamReader.hpp +++ b/src/clp_ffi_js/ir/IrStreamReader.hpp @@ -61,7 +61,7 @@ class IrStreamReader : public StreamReader { * * @param log_level_filter Array of selected log levels */ - void filter_log_events(emscripten::val const& log_level_filter) override; + void filter_log_events(LogLevelFilterTsType const& log_level_filter) override; /** * Deserializes all log events in the stream. After the stream has been exhausted, it will be diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index 7c957585..ee63bac5 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -58,11 +58,14 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< namespace { EMSCRIPTEN_BINDINGS(ClpStreamReader) { + // Output to JS types emscripten::register_type("Uint8Array"); emscripten::register_type( "Array<[string, number, number, number]>" ); emscripten::register_type("number[] | null"); + // Input from JS types + emscripten::register_type("number[] | null"); emscripten::class_("ClpStreamReader") .constructor( &clp_ffi_js::ir::StreamReader::create, diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index b0d6e671..65c4c555 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -13,6 +13,7 @@ namespace clp_ffi_js::ir { EMSCRIPTEN_DECLARE_VAL_TYPE(DataArrayTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(DecodedResultsTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(FilteredLogEventMapTsType); +EMSCRIPTEN_DECLARE_VAL_TYPE(LogLevelFilterTsType); constexpr std::array cIrV1Versions = {"v0.0.1", "v0.0.0", "0.0.1", "0.0.0"}; @@ -60,7 +61,7 @@ class StreamReader { * * @param log_level_filter Array of selected log levels */ - virtual void filter_log_events(emscripten::val const& log_level_filter) = 0; + virtual void filter_log_events(LogLevelFilterTsType const& log_level_filter) = 0; /** * Deserializes all log events in the stream. After the stream has been exhausted, it will be From 6e8d025c12e9292271b9d201bf8406755c3608c3 Mon Sep 17 00:00:00 2001 From: davemarco <83603688+davemarco@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:48:21 -0500 Subject: [PATCH 20/40] Update src/clp_ffi_js/ir/StreamReader.hpp Co-authored-by: Junhao Liao --- src/clp_ffi_js/ir/StreamReader.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index 65c4c555..0bb62bdf 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -15,7 +15,8 @@ EMSCRIPTEN_DECLARE_VAL_TYPE(DecodedResultsTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(FilteredLogEventMapTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(LogLevelFilterTsType); -constexpr std::array cIrV1Versions = {"v0.0.1", "v0.0.0", "0.0.1", "0.0.0"}; +constexpr std::array cIrV1Versions + = {"v0.0.2", "v0.0.1", "v0.0.0", "0.0.2", "0.0.1", "0.0.0"}; /** * Class to deserialize and decode Zstandard-compressed CLP IR streams as well as format decoded From 19e41b99239a2e112c141f8220c8bea418135ce6 Mon Sep 17 00:00:00 2001 From: davemarco <83603688+davemarco@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:48:44 -0500 Subject: [PATCH 21/40] Update src/clp_ffi_js/ir/StreamReader.cpp Co-authored-by: Junhao Liao --- src/clp_ffi_js/ir/StreamReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index ee63bac5..66a5dd25 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -51,7 +51,7 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< clp::ErrorCode::ErrorCode_Unsupported, __FILENAME__, __LINE__, - std::format("Unable to create stream reader for IR data with version {}.", version) + std::format("Unable to create reader for CLP stream with version {}.", version) }; } } // namespace clp_ffi_js::ir From 49889491ab404729721f5967298dc2361abbe638 Mon Sep 17 00:00:00 2001 From: davemarco <83603688+davemarco@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:49:11 -0500 Subject: [PATCH 22/40] Update src/clp_ffi_js/ir/decoding_methods.hpp Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- src/clp_ffi_js/ir/decoding_methods.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/clp_ffi_js/ir/decoding_methods.hpp b/src/clp_ffi_js/ir/decoding_methods.hpp index d80989f4..d076357c 100644 --- a/src/clp_ffi_js/ir/decoding_methods.hpp +++ b/src/clp_ffi_js/ir/decoding_methods.hpp @@ -15,6 +15,7 @@ namespace clp_ffi_js::ir { * @return Stream version. */ auto get_version(clp::ReaderInterface& reader) -> std::string; + /** * Rewinds the reader to the beginning and validates the CLP IR data encoding type. * @param reader From c79a83f126ddddc241d693e8579d3a02f08be4c5 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Tue, 5 Nov 2024 22:52:39 +0000 Subject: [PATCH 23/40] kirk review comments --- src/clp_ffi_js/ir/StreamReader.cpp | 2 +- src/clp_ffi_js/ir/StreamReader.hpp | 2 +- src/clp_ffi_js/ir/decoding_methods.hpp | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index 66a5dd25..b9cf69b8 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -35,7 +35,7 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< auto const version{get_version(*zstd_decompressor)}; - if (std::ranges::find(cIrV1Versions, version) != cIrV1Versions.end()) { + if (std::ranges::find(cTextIrVersions, version) != cTextIrVersions.end()) { auto stream_reader_data_context{IrStreamReader::create_data_context( std::move(zstd_decompressor), std::move(data_buffer) diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index 0bb62bdf..c9396085 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -15,7 +15,7 @@ EMSCRIPTEN_DECLARE_VAL_TYPE(DecodedResultsTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(FilteredLogEventMapTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(LogLevelFilterTsType); -constexpr std::array cIrV1Versions +constexpr std::array cTextIrVersions = {"v0.0.2", "v0.0.1", "v0.0.0", "0.0.2", "0.0.1", "0.0.0"}; /** diff --git a/src/clp_ffi_js/ir/decoding_methods.hpp b/src/clp_ffi_js/ir/decoding_methods.hpp index d076357c..eb68746d 100644 --- a/src/clp_ffi_js/ir/decoding_methods.hpp +++ b/src/clp_ffi_js/ir/decoding_methods.hpp @@ -7,22 +7,22 @@ namespace clp_ffi_js::ir { /** - * Gets the version of the IR stream from the specified reader. + * Rewinds the reader to the beginning and validates the CLP IR data encoding type. * @param reader * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is * unsupported. - * @throws ClpFfiJsException if the preamble could not be deserialized. - * @return Stream version. */ -auto get_version(clp::ReaderInterface& reader) -> std::string; +auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void; +} // namespace clp_ffi_js::ir /** - * Rewinds the reader to the beginning and validates the CLP IR data encoding type. + * Gets the version of the IR stream from the specified reader. * @param reader * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is * unsupported. + * @throws ClpFfiJsException if the preamble could not be deserialized. + * @return Stream version. */ -auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void; -} // namespace clp_ffi_js::ir +auto get_version(clp::ReaderInterface& reader) -> std::string; #endif // CLP_FFI_JS_IR_DECODING_METHODS_HPP From ef0b86b9f8dc9097bc63c724df786f14d9230cd0 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Tue, 5 Nov 2024 23:27:07 +0000 Subject: [PATCH 24/40] fix lint --- src/clp_ffi_js/ir/decoding_methods.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/clp_ffi_js/ir/decoding_methods.hpp b/src/clp_ffi_js/ir/decoding_methods.hpp index eb68746d..68324d1d 100644 --- a/src/clp_ffi_js/ir/decoding_methods.hpp +++ b/src/clp_ffi_js/ir/decoding_methods.hpp @@ -13,7 +13,6 @@ namespace clp_ffi_js::ir { * unsupported. */ auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void; -} // namespace clp_ffi_js::ir /** * Gets the version of the IR stream from the specified reader. @@ -24,5 +23,5 @@ auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> v * @return Stream version. */ auto get_version(clp::ReaderInterface& reader) -> std::string; - +} // namespace clp_ffi_js::ir #endif // CLP_FFI_JS_IR_DECODING_METHODS_HPP From d9e9e97e07fab98ac747e53590363c43fa1dbb0e Mon Sep 17 00:00:00 2001 From: davemarco <83603688+davemarco@users.noreply.github.com> Date: Tue, 5 Nov 2024 21:26:28 -0500 Subject: [PATCH 25/40] Apply suggestions from code review Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- src/clp_ffi_js/ir/IrStreamReader.hpp | 29 +++----------------------- src/clp_ffi_js/ir/StreamReader.cpp | 6 +++--- src/clp_ffi_js/ir/decoding_methods.cpp | 6 +++--- src/clp_ffi_js/ir/decoding_methods.hpp | 7 +++---- 4 files changed, 12 insertions(+), 36 deletions(-) diff --git a/src/clp_ffi_js/ir/IrStreamReader.hpp b/src/clp_ffi_js/ir/IrStreamReader.hpp index ba649747..84b29783 100644 --- a/src/clp_ffi_js/ir/IrStreamReader.hpp +++ b/src/clp_ffi_js/ir/IrStreamReader.hpp @@ -26,8 +26,8 @@ using clp::ir::four_byte_encoded_variable_t; using FilteredLogEventsMap = std::optional>; /** - * Class to deserialize and decode Zstandard-compressed CLP IRv1 streams as well as format decoded - * log events. + * Class to deserialize and decode Zstd-compressed CLP unstructured IR streams, as well as format + * decoded log events. */ class IrStreamReader : public StreamReader { friend StreamReader; @@ -51,16 +51,8 @@ class IrStreamReader : public StreamReader { */ [[nodiscard]] auto get_num_events_buffered() const -> size_t override; - /** - * @return The filtered log events map. - */ [[nodiscard]] auto get_filtered_log_event_map() const -> FilteredLogEventMapTsType override; - /** - * Generates a filtered collection from all log events. - * - * @param log_level_filter Array of selected log levels - */ void filter_log_events(LogLevelFilterTsType const& log_level_filter) override; /** @@ -71,27 +63,12 @@ class IrStreamReader : public StreamReader { */ [[nodiscard]] auto deserialize_stream() -> size_t override; - /** - * Decodes log events in the range `[beginIdx, endIdx)` of the filtered or unfiltered - * (depending on the value of `useFilter`) log events collection. - * - * @param begin_idx - * @param end_idx - * @param use_filter Whether to decode from the filtered or unfiltered log events collection. - * @return An array where each element is a decoded log event represented by an array of: - * - The log event's message - * - The log event's timestamp as milliseconds since the Unix epoch - * - The log event's log level as an integer that indexes into `cLogLevelNames` - * - The log event's number (1-indexed) in the stream - * @return null if any log event in the range doesn't exist (e.g. the range exceeds the number - * of log events in the collection). - */ [[nodiscard]] auto decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const -> DecodedResultsTsType override; private: // Constructor - IrStreamReader( + explicit IrStreamReader( StreamReaderDataContext&& stream_reader_data_context ); diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index b9cf69b8..86e712c2 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -45,7 +45,6 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< new IrStreamReader(std::move(stream_reader_data_context)) ); } - SPDLOG_CRITICAL("Unable to create reader for CLP stream with version {}.", version); throw ClpFfiJsException{ clp::ErrorCode::ErrorCode_Unsupported, @@ -58,13 +57,14 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< namespace { EMSCRIPTEN_BINDINGS(ClpStreamReader) { - // Output to JS types + // JS types used as outputs emscripten::register_type("Uint8Array"); emscripten::register_type( "Array<[string, number, number, number]>" ); emscripten::register_type("number[] | null"); - // Input from JS types + + // JS types used as inputs emscripten::register_type("number[] | null"); emscripten::class_("ClpStreamReader") .constructor( diff --git a/src/clp_ffi_js/ir/decoding_methods.cpp b/src/clp_ffi_js/ir/decoding_methods.cpp index eb282fbe..ded08a3b 100644 --- a/src/clp_ffi_js/ir/decoding_methods.cpp +++ b/src/clp_ffi_js/ir/decoding_methods.cpp @@ -55,7 +55,7 @@ auto get_version(clp::ReaderInterface& reader) -> std::string { }; if (clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != deserialize_preamble_result) { SPDLOG_CRITICAL( - "Failed to deserialize preamble for version reading: {}", + "Failed to deserialize stream's preamble: {}", clp::enum_to_underlying_type(deserialize_preamble_result) ); @@ -70,7 +70,7 @@ auto get_version(clp::ReaderInterface& reader) -> std::string { }; } - // Deserialize metadata bytes which is encoded in JSON. + // Deserialize metadata bytes as JSON. std::string_view const metadata_view{ clp::size_checked_pointer_cast(metadata_bytes.data()), metadata_bytes.size() @@ -85,7 +85,7 @@ auto get_version(clp::ReaderInterface& reader) -> std::string { clp::ErrorCode::ErrorCode_MetadataCorrupted, __FILENAME__, __LINE__, - std::format("Error parsing stream metadata: {}", e.what()) + std::format("Failed to parse stream's metadata: {}", e.what()) }; } diff --git a/src/clp_ffi_js/ir/decoding_methods.hpp b/src/clp_ffi_js/ir/decoding_methods.hpp index 68324d1d..ceeb55f7 100644 --- a/src/clp_ffi_js/ir/decoding_methods.hpp +++ b/src/clp_ffi_js/ir/decoding_methods.hpp @@ -17,10 +17,9 @@ auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> v /** * Gets the version of the IR stream from the specified reader. * @param reader - * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is - * unsupported. - * @throws ClpFfiJsException if the preamble could not be deserialized. - * @return Stream version. + * @throws Propagates `rewind_reader_and_validate_encoding_type`'s exceptions. + * @throws ClpFfiJsException if the preamble couldn't be deserialized. + * @return The stream's version. */ auto get_version(clp::ReaderInterface& reader) -> std::string; } // namespace clp_ffi_js::ir From efaeeddd4c85e39b7a47fb96d39a3de1b93bada9 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Wed, 6 Nov 2024 04:17:00 +0000 Subject: [PATCH 26/40] kirk review --- CMakeLists.txt | 3 +- src/clp_ffi_js/ir/IrStreamReader.cpp | 224 ------------------------- src/clp_ffi_js/ir/IrStreamReader.hpp | 90 ---------- src/clp_ffi_js/ir/StreamReader.cpp | 99 +++++++++-- src/clp_ffi_js/ir/StreamReader.hpp | 28 +++- src/clp_ffi_js/ir/decoding_methods.cpp | 95 ----------- src/clp_ffi_js/ir/decoding_methods.hpp | 26 --- 7 files changed, 114 insertions(+), 451 deletions(-) delete mode 100644 src/clp_ffi_js/ir/IrStreamReader.cpp delete mode 100644 src/clp_ffi_js/ir/IrStreamReader.hpp delete mode 100644 src/clp_ffi_js/ir/decoding_methods.cpp delete mode 100644 src/clp_ffi_js/ir/decoding_methods.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d584386..6b6d65a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,8 +113,7 @@ target_include_directories( target_include_directories(${CLP_FFI_JS_BIN_NAME} PRIVATE src/) set(CLP_FFI_JS_SRC_MAIN - src/clp_ffi_js/ir/decoding_methods.cpp - src/clp_ffi_js/ir/IrStreamReader.cpp + src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp src/clp_ffi_js/ir/StreamReader.cpp ) diff --git a/src/clp_ffi_js/ir/IrStreamReader.cpp b/src/clp_ffi_js/ir/IrStreamReader.cpp deleted file mode 100644 index 381e4144..00000000 --- a/src/clp_ffi_js/ir/IrStreamReader.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include "IrStreamReader.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace clp_ffi_js::ir { - -using namespace std::literals::string_literals; -using clp::ir::four_byte_encoded_variable_t; - -auto IrStreamReader::get_num_events_buffered() const -> size_t { - return m_encoded_log_events.size(); -} - -auto IrStreamReader::get_filtered_log_event_map() const -> FilteredLogEventMapTsType { - if (false == m_filtered_log_event_map.has_value()) { - return FilteredLogEventMapTsType{emscripten::val::null()}; - } - - return FilteredLogEventMapTsType{emscripten::val::array(m_filtered_log_event_map.value())}; -} - -void IrStreamReader::filter_log_events(LogLevelFilterTsType const& log_level_filter) { - if (log_level_filter.isNull()) { - m_filtered_log_event_map.reset(); - return; - } - - m_filtered_log_event_map.emplace(); - auto filter_levels{emscripten::vecFromJSArray>(log_level_filter - )}; - for (size_t log_event_idx = 0; log_event_idx < m_encoded_log_events.size(); ++log_event_idx) { - auto const& log_event = m_encoded_log_events[log_event_idx]; - if (std::ranges::find( - filter_levels, - clp::enum_to_underlying_type(log_event.get_log_level()) - ) - != filter_levels.end()) - { - m_filtered_log_event_map->emplace_back(log_event_idx); - } - } -} - -auto IrStreamReader::deserialize_stream() -> size_t { - if (nullptr == m_stream_reader_data_context) { - return m_encoded_log_events.size(); - } - - constexpr size_t cDefaultNumReservedLogEvents{500'000}; - m_encoded_log_events.reserve(cDefaultNumReservedLogEvents); - - while (true) { - auto result{m_stream_reader_data_context->get_deserializer().deserialize_log_event()}; - if (result.has_error()) { - auto const error{result.error()}; - if (std::errc::no_message_available == error) { - break; - } - if (std::errc::result_out_of_range == error) { - SPDLOG_ERROR("File contains an incomplete IR stream"); - break; - } - throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_Corrupt, - __FILENAME__, - __LINE__, - "Failed to deserialize: "s + error.category().name() + ":" + error.message() - }; - } - auto const& log_event = result.value(); - auto const& message = log_event.get_message(); - - auto const& logtype = message.get_logtype(); - constexpr size_t cLogLevelPositionInMessages{1}; - LogLevel log_level{LogLevel::NONE}; - if (logtype.length() > cLogLevelPositionInMessages) { - // NOLINTNEXTLINE(readability-qualified-auto) - auto const log_level_name_it{std::find_if( - cLogLevelNames.begin() + static_cast(cValidLogLevelsBeginIdx), - cLogLevelNames.end(), - [&](std::string_view level) { - return logtype.substr(cLogLevelPositionInMessages).starts_with(level); - } - )}; - if (log_level_name_it != cLogLevelNames.end()) { - log_level = static_cast( - std::distance(cLogLevelNames.begin(), log_level_name_it) - ); - } - } - - auto log_viewer_event{LogEventWithLevel( - log_event.get_timestamp(), - log_event.get_utc_offset(), - message, - log_level - )}; - m_encoded_log_events.emplace_back(std::move(log_viewer_event)); - } - m_stream_reader_data_context.reset(nullptr); - return m_encoded_log_events.size(); -} - -auto IrStreamReader::decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const - -> DecodedResultsTsType { - if (use_filter && false == m_filtered_log_event_map.has_value()) { - return DecodedResultsTsType{emscripten::val::null()}; - } - - size_t length{0}; - if (use_filter) { - length = m_filtered_log_event_map->size(); - } else { - length = m_encoded_log_events.size(); - } - if (length < end_idx || begin_idx > end_idx) { - return DecodedResultsTsType{emscripten::val::null()}; - } - - std::string message; - constexpr size_t cDefaultReservedMessageLength{512}; - message.reserve(cDefaultReservedMessageLength); - auto const results{emscripten::val::array()}; - - for (size_t i = begin_idx; i < end_idx; ++i) { - size_t log_event_idx{0}; - if (use_filter) { - log_event_idx = m_filtered_log_event_map->at(i); - } else { - log_event_idx = i; - } - auto const& log_event{m_encoded_log_events[log_event_idx]}; - - auto const parsed{log_event.get_message().decode_and_unparse()}; - if (false == parsed.has_value()) { - SPDLOG_ERROR("Failed to decode message."); - throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_Failure, - __FILENAME__, - __LINE__, - "Failed to decode message" - }; - } - message = parsed.value(); - - m_ts_pattern.insert_formatted_timestamp(log_event.get_timestamp(), message); - - EM_ASM( - { Emval.toValue($0).push([UTF8ToString($1), $2, $3, $4]); }, - results.as_handle(), - message.c_str(), - log_event.get_timestamp(), - log_event.get_log_level(), - log_event_idx + 1 - ); - } - - return DecodedResultsTsType(results); -} - -IrStreamReader::IrStreamReader( - StreamReaderDataContext&& stream_reader_data_context -) - : m_stream_reader_data_context{std::make_unique< - StreamReaderDataContext>( - std::move(stream_reader_data_context) - )}, - m_ts_pattern{m_stream_reader_data_context->get_deserializer().get_timestamp_pattern()} {} - -auto IrStreamReader::create_data_context( - std::unique_ptr&& zstd_decompressor, - clp::Array&& data_buffer -) -> StreamReaderDataContext { - rewind_reader_and_validate_encoding_type(*zstd_decompressor); - auto result{ - clp::ir::LogEventDeserializer::create(*zstd_decompressor) - }; - if (result.has_error()) { - auto const error_code{result.error()}; - SPDLOG_CRITICAL( - "Failed to create deserializer: {}:{}", - error_code.category().name(), - error_code.message() - ); - throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_Failure, - __FILENAME__, - __LINE__, - "Failed to create deserializer" - }; - } - - return {std::move(data_buffer), std::move(zstd_decompressor), std::move(result.value())}; -} -} // namespace clp_ffi_js::ir diff --git a/src/clp_ffi_js/ir/IrStreamReader.hpp b/src/clp_ffi_js/ir/IrStreamReader.hpp deleted file mode 100644 index 84b29783..00000000 --- a/src/clp_ffi_js/ir/IrStreamReader.hpp +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef CLP_FFI_JS_IR_IR_STREAM_READER_HPP -#define CLP_FFI_JS_IR_IR_STREAM_READER_HPP - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -namespace clp_ffi_js::ir { -using clp::ir::four_byte_encoded_variable_t; - -/** - * Mapping between an index in the filtered log events collection to an index in the unfiltered - * log events collection. - */ -using FilteredLogEventsMap = std::optional>; - -/** - * Class to deserialize and decode Zstd-compressed CLP unstructured IR streams, as well as format - * decoded log events. - */ -class IrStreamReader : public StreamReader { - friend StreamReader; - -public: - // Destructor - ~IrStreamReader() override = default; - - // Disable copy constructor and assignment operator - IrStreamReader(IrStreamReader const&) = delete; - auto operator=(IrStreamReader const&) -> IrStreamReader& = delete; - - // Define default move constructor - IrStreamReader(IrStreamReader&&) = default; - // Delete move assignment operator since it's also disabled in `clp::ir::LogEventDeserializer`. - auto operator=(IrStreamReader&&) -> IrStreamReader& = delete; - - // Methods - /** - * @return The number of events buffered. - */ - [[nodiscard]] auto get_num_events_buffered() const -> size_t override; - - [[nodiscard]] auto get_filtered_log_event_map() const -> FilteredLogEventMapTsType override; - - void filter_log_events(LogLevelFilterTsType const& log_level_filter) override; - - /** - * Deserializes all log events in the stream. After the stream has been exhausted, it will be - * deallocated. - * - * @return The number of successfully deserialized ("valid") log events. - */ - [[nodiscard]] auto deserialize_stream() -> size_t override; - - [[nodiscard]] auto decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const - -> DecodedResultsTsType override; - -private: - // Constructor - explicit IrStreamReader( - StreamReaderDataContext&& stream_reader_data_context - ); - - // Methods - [[nodiscard]] static auto create_data_context( - std::unique_ptr&& zstd_decompressor, - clp::Array&& data_buffer - ) -> StreamReaderDataContext; - - // Variables - std::vector> m_encoded_log_events; - std::unique_ptr> - m_stream_reader_data_context; - FilteredLogEventsMap m_filtered_log_event_map; - clp::TimestampPattern m_ts_pattern; -}; -} // namespace clp_ffi_js::ir - -#endif // CLP_FFI_JS_IR_IR_STREAM_READER_HPP diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index 86e712c2..8f07096e 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -5,20 +5,96 @@ #include #include #include +#include +#include #include +#include #include #include +#include #include #include +#include + +#include +#include + +#include +#include + +#include #include #include -#include -#include -#include namespace clp_ffi_js::ir { + +auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void { + reader.seek_from_begin(0); + + bool is_four_bytes_encoding{true}; + if (auto const err{clp::ffi::ir_stream::get_encoding_type(reader, is_four_bytes_encoding)}; + clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != err) + { + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_MetadataCorrupted, + __FILENAME__, + __LINE__, + std::format("Failed to decode encoding type, err={}", clp::enum_to_underlying_type(err)) + }; + } + if (false == is_four_bytes_encoding) { + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_Unsupported, + __FILENAME__, + __LINE__, + "IR stream uses unsupported encoding." + }; + } +} + +auto get_version(clp::ReaderInterface& reader) -> std::string { + // Deserialize metadata bytes from preamble. + clp::ffi::ir_stream::encoded_tag_t metadata_type{}; + std::vector metadata_bytes; + auto const deserialize_preamble_result{ + clp::ffi::ir_stream::deserialize_preamble(reader, metadata_type, metadata_bytes) + }; + if (clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != deserialize_preamble_result) { + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_Failure, + __FILENAME__, + __LINE__, + std::format( + "Failed to deserialize preamble for version reading: {}", + clp::enum_to_underlying_type(deserialize_preamble_result) + ) + }; + } + + std::string version; + try { + // Deserialize metadata bytes as JSON. + std::string_view const metadata_view{ + clp::size_checked_pointer_cast(metadata_bytes.data()), + metadata_bytes.size() + }; + nlohmann::json const metadata = nlohmann::json::parse(metadata_view); + version = metadata.at(clp::ffi::ir_stream::cProtocol::Metadata::VersionKey); + } catch (nlohmann::json::exception const& e) { + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_MetadataCorrupted, + __FILENAME__, + __LINE__, + std::format("Failed to parse stream's metadata: {}", e.what()) + }; + } + + SPDLOG_INFO("The version is {}", version); + return version; +} + auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr { auto const length{data_array["length"].as()}; SPDLOG_INFO("StreamReader::create: got buffer of length={}", length); @@ -30,19 +106,22 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< .call("set", data_array, reinterpret_cast(data_buffer.data())); // NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast) - auto zstd_decompressor{std::make_unique()}; + auto zstd_decompressor{std::make_unique()}; zstd_decompressor->open(data_buffer.data(), length); + size_t reader_offset = 0; + rewind_reader_and_validate_encoding_type(*zstd_decompressor); + reader_offset = zstd_decompressor->try_get_pos(reader_offset); + + // Required to validate encoding type prior to getting version. auto const version{get_version(*zstd_decompressor)}; + // Required that reader offset matches position after validation in order to decode log events. + zstd_decompressor->seek_from_begin(reader_offset); - if (std::ranges::find(cTextIrVersions, version) != cTextIrVersions.end()) { - auto stream_reader_data_context{IrStreamReader::create_data_context( + if (std::ranges::find(cUnstructuredIrVersions, version) != cUnstructuredIrVersions.end()) { + return UnstructuredIrStreamReader::create( std::move(zstd_decompressor), std::move(data_buffer) - )}; - - return std::unique_ptr( - new IrStreamReader(std::move(stream_reader_data_context)) ); } diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index c9396085..edb6790c 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -6,6 +6,7 @@ #include #include +#include #include namespace clp_ffi_js::ir { @@ -15,17 +16,36 @@ EMSCRIPTEN_DECLARE_VAL_TYPE(DecodedResultsTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(FilteredLogEventMapTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(LogLevelFilterTsType); -constexpr std::array cTextIrVersions +constexpr std::array cUnstructuredIrVersions = {"v0.0.2", "v0.0.1", "v0.0.0", "0.0.2", "0.0.1", "0.0.0"}; +/** +* Rewinds the reader to the beginning and validates the CLP IR data encoding type. +* @param reader +* @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is +* unsupported. +*/ +static auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void; + +/** +* Gets the version of the IR stream from the specified reader. +* @param reader +* @throws Propagates `rewind_reader_and_validate_encoding_type`'s exceptions. +* @throws ClpFfiJsException if the preamble couldn't be deserialized. +* @return The stream's version. +*/ +static auto get_version(clp::ReaderInterface& reader) -> std::string; + /** * Class to deserialize and decode Zstandard-compressed CLP IR streams as well as format decoded * log events. */ class StreamReader { public: + using ZstdDecompressor = clp::streaming_compression::zstd::Decompressor; + /** - * Creates a StreamReader to read from the given array. + * Creates a `StreamReader` to read from the given array. * * @param data_array An array containing a Zstandard-compressed IR stream. * @return The created instance. @@ -47,6 +67,7 @@ class StreamReader { auto operator=(StreamReader&&) -> StreamReader& = delete; // Methods + /** * @return The number of events buffered. */ @@ -65,8 +86,7 @@ class StreamReader { virtual void filter_log_events(LogLevelFilterTsType const& log_level_filter) = 0; /** - * Deserializes all log events in the stream. After the stream has been exhausted, it will be - * deallocated. + * Deserializes all log events in the stream. * * @return The number of successfully deserialized ("valid") log events. */ diff --git a/src/clp_ffi_js/ir/decoding_methods.cpp b/src/clp_ffi_js/ir/decoding_methods.cpp deleted file mode 100644 index ded08a3b..00000000 --- a/src/clp_ffi_js/ir/decoding_methods.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "decoding_methods.hpp" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace clp_ffi_js::ir { -auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void { - reader.seek_from_begin(0); - - bool is_four_bytes_encoding{true}; - if (auto const err{clp::ffi::ir_stream::get_encoding_type(reader, is_four_bytes_encoding)}; - clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != err) - { - SPDLOG_CRITICAL("Failed to decode encoding type, err={}", err); - throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_MetadataCorrupted, - __FILENAME__, - __LINE__, - "Failed to decode encoding type." - }; - } - if (false == is_four_bytes_encoding) { - throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_Unsupported, - __FILENAME__, - __LINE__, - "IR stream uses unsupported encoding." - }; - } -} - -auto get_version(clp::ReaderInterface& reader) -> std::string { - // The encoding type bytes must be consumed before the metadata can be read. - rewind_reader_and_validate_encoding_type(reader); - - // Deserialize metadata bytes from preamble. - clp::ffi::ir_stream::encoded_tag_t metadata_type{}; - std::vector metadata_bytes; - auto const deserialize_preamble_result{ - clp::ffi::ir_stream::deserialize_preamble(reader, metadata_type, metadata_bytes) - }; - if (clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != deserialize_preamble_result) { - SPDLOG_CRITICAL( - "Failed to deserialize stream's preamble: {}", - clp::enum_to_underlying_type(deserialize_preamble_result) - ); - - throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_Failure, - __FILENAME__, - __LINE__, - std::format( - "Failed to deserialize preamble for version reading: {}", - clp::enum_to_underlying_type(deserialize_preamble_result) - ) - }; - } - - // Deserialize metadata bytes as JSON. - std::string_view const metadata_view{ - clp::size_checked_pointer_cast(metadata_bytes.data()), - metadata_bytes.size() - }; - - std::string version; - try { - nlohmann::json const metadata = nlohmann::json::parse(metadata_view); - version = metadata.at(clp::ffi::ir_stream::cProtocol::Metadata::VersionKey); - } catch (nlohmann::json::exception const& e) { - throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_MetadataCorrupted, - __FILENAME__, - __LINE__, - std::format("Failed to parse stream's metadata: {}", e.what()) - }; - } - - SPDLOG_INFO("The version is {}", version); - return version; -} -} // namespace clp_ffi_js::ir diff --git a/src/clp_ffi_js/ir/decoding_methods.hpp b/src/clp_ffi_js/ir/decoding_methods.hpp deleted file mode 100644 index ceeb55f7..00000000 --- a/src/clp_ffi_js/ir/decoding_methods.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef CLP_FFI_JS_IR_DECODING_METHODS_HPP -#define CLP_FFI_JS_IR_DECODING_METHODS_HPP - -#include - -#include - -namespace clp_ffi_js::ir { -/** - * Rewinds the reader to the beginning and validates the CLP IR data encoding type. - * @param reader - * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is - * unsupported. - */ -auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void; - -/** - * Gets the version of the IR stream from the specified reader. - * @param reader - * @throws Propagates `rewind_reader_and_validate_encoding_type`'s exceptions. - * @throws ClpFfiJsException if the preamble couldn't be deserialized. - * @return The stream's version. - */ -auto get_version(clp::ReaderInterface& reader) -> std::string; -} // namespace clp_ffi_js::ir -#endif // CLP_FFI_JS_IR_DECODING_METHODS_HPP From 3764298a7bdb818bdce994dd61e0b9889db78468 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Wed, 6 Nov 2024 04:19:25 +0000 Subject: [PATCH 27/40] rename --- .../ir/UnstructuredIrStreamReader.cpp | 233 ++++++++++++++++++ .../ir/UnstructuredIrStreamReader.hpp | 85 +++++++ 2 files changed, 318 insertions(+) create mode 100644 src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp create mode 100644 src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp diff --git a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp new file mode 100644 index 00000000..8fa7cebc --- /dev/null +++ b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp @@ -0,0 +1,233 @@ +#include "UnstructuredIrStreamReader.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace clp_ffi_js::ir { + +using namespace std::literals::string_literals; +using clp::ir::four_byte_encoded_variable_t; + +auto UnstructuredIrStreamReader::create( + std::unique_ptr&& zstd_decompressor, + clp::Array&& data_array +) -> std::unique_ptr { + + auto result{ + clp::ir::LogEventDeserializer::create(*zstd_decompressor) + }; + if (result.has_error()) { + auto const error_code{result.error()}; + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_Failure, + __FILENAME__, + __LINE__, + std::format( + "Failed to create deserializer: {} {}", + error_code.category().name(), + error_code.message() + ) + }; + } + auto data_context = StreamReaderDataContext( + std::move(data_array), + std::move(zstd_decompressor), + std::move(result.value()) + ); + return std::make_unique( + UnstructuredIrStreamReader(std::move(data_context)) + ); +} + +auto UnstructuredIrStreamReader::get_num_events_buffered() const -> size_t { + return m_encoded_log_events.size(); +} + +auto UnstructuredIrStreamReader::get_filtered_log_event_map() const -> FilteredLogEventMapTsType { + if (false == m_filtered_log_event_map.has_value()) { + return FilteredLogEventMapTsType{emscripten::val::null()}; + } + + return FilteredLogEventMapTsType{emscripten::val::array(m_filtered_log_event_map.value())}; +} + +void UnstructuredIrStreamReader::filter_log_events(LogLevelFilterTsType const& log_level_filter) { + if (log_level_filter.isNull()) { + m_filtered_log_event_map.reset(); + return; + } + + m_filtered_log_event_map.emplace(); + auto filter_levels{emscripten::vecFromJSArray>(log_level_filter + )}; + for (size_t log_event_idx = 0; log_event_idx < m_encoded_log_events.size(); ++log_event_idx) { + auto const& log_event = m_encoded_log_events[log_event_idx]; + if (std::ranges::find( + filter_levels, + clp::enum_to_underlying_type(log_event.get_log_level()) + ) + != filter_levels.end()) + { + m_filtered_log_event_map->emplace_back(log_event_idx); + } + } +} + +auto UnstructuredIrStreamReader::deserialize_stream() -> size_t { + if (nullptr == m_stream_reader_data_context) { + return m_encoded_log_events.size(); + } + + constexpr size_t cDefaultNumReservedLogEvents{500'000}; + m_encoded_log_events.reserve(cDefaultNumReservedLogEvents); + + while (true) { + auto result{m_stream_reader_data_context->get_deserializer().deserialize_log_event()}; + if (result.has_error()) { + auto const error{result.error()}; + if (std::errc::no_message_available == error) { + break; + } + if (std::errc::result_out_of_range == error) { + SPDLOG_ERROR("File contains an incomplete IR stream"); + break; + } + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_Corrupt, + __FILENAME__, + __LINE__, + std::format( + "Failed to deserialize: {}:{}", + error.category().name(), + error.message() + ) + }; + } + auto const& log_event = result.value(); + auto const& message = log_event.get_message(); + + auto const& logtype = message.get_logtype(); + constexpr size_t cLogLevelPositionInMessages{1}; + LogLevel log_level{LogLevel::NONE}; + if (logtype.length() > cLogLevelPositionInMessages) { + // NOLINTNEXTLINE(readability-qualified-auto) + auto const log_level_name_it{std::find_if( + cLogLevelNames.begin() + static_cast(cValidLogLevelsBeginIdx), + cLogLevelNames.end(), + [&](std::string_view level) { + return logtype.substr(cLogLevelPositionInMessages).starts_with(level); + } + )}; + if (log_level_name_it != cLogLevelNames.end()) { + log_level = static_cast( + std::distance(cLogLevelNames.begin(), log_level_name_it) + ); + } + } + + auto log_viewer_event{LogEventWithLevel( + log_event.get_timestamp(), + log_event.get_utc_offset(), + message, + log_level + )}; + m_encoded_log_events.emplace_back(std::move(log_viewer_event)); + } + m_stream_reader_data_context.reset(nullptr); + return m_encoded_log_events.size(); +} + +auto UnstructuredIrStreamReader::decode_range(size_t begin_idx, size_t end_idx, bool use_filter) + const -> DecodedResultsTsType { + if (use_filter && false == m_filtered_log_event_map.has_value()) { + return DecodedResultsTsType{emscripten::val::null()}; + } + + size_t length{0}; + if (use_filter) { + length = m_filtered_log_event_map->size(); + } else { + length = m_encoded_log_events.size(); + } + if (length < end_idx || begin_idx > end_idx) { + return DecodedResultsTsType{emscripten::val::null()}; + } + + std::string message; + constexpr size_t cDefaultReservedMessageLength{512}; + message.reserve(cDefaultReservedMessageLength); + auto const results{emscripten::val::array()}; + + for (size_t i = begin_idx; i < end_idx; ++i) { + size_t log_event_idx{0}; + if (use_filter) { + log_event_idx = m_filtered_log_event_map->at(i); + } else { + log_event_idx = i; + } + auto const& log_event{m_encoded_log_events[log_event_idx]}; + + auto const parsed{log_event.get_message().decode_and_unparse()}; + if (false == parsed.has_value()) { + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_Failure, + __FILENAME__, + __LINE__, + "Failed to decode message" + }; + } + message = parsed.value(); + + m_ts_pattern.insert_formatted_timestamp(log_event.get_timestamp(), message); + + EM_ASM( + { Emval.toValue($0).push([UTF8ToString($1), $2, $3, $4]); }, + results.as_handle(), + message.c_str(), + log_event.get_timestamp(), + log_event.get_log_level(), + log_event_idx + 1 + ); + } + + return DecodedResultsTsType(results); +} + +UnstructuredIrStreamReader::UnstructuredIrStreamReader( + StreamReaderDataContext&& stream_reader_data_context +) + : m_stream_reader_data_context{std::make_unique< + StreamReaderDataContext>( + std::move(stream_reader_data_context) + )}, + m_ts_pattern{m_stream_reader_data_context->get_deserializer().get_timestamp_pattern()} {} + +} // namespace clp_ffi_js::ir diff --git a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp new file mode 100644 index 00000000..0fbce93c --- /dev/null +++ b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp @@ -0,0 +1,85 @@ +#ifndef CLP_FFI_JS_IR_UNSTRUCTUREDUnstructuredIrStreamReader_HPP +#define CLP_FFI_JS_IR_UNSTRUCTUREDUnstructuredIrStreamReader_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace clp_ffi_js::ir { +using clp::ir::four_byte_encoded_variable_t; + +/** + * Mapping between an index in the filtered log events collection to an index in the unfiltered + * log events collection. + */ +using FilteredLogEventsMap = std::optional>; + +/** + * Class to deserialize and decode Zstd-compressed CLP unstructured IR streams, as well as format + * decoded log events. + */ +class UnstructuredIrStreamReader : public StreamReader { + friend StreamReader; + +public: + // Destructor + ~UnstructuredIrStreamReader() override = default; + + // Disable copy constructor and assignment operator + UnstructuredIrStreamReader(UnstructuredIrStreamReader const&) = delete; + auto operator=(UnstructuredIrStreamReader const&) -> UnstructuredIrStreamReader& = delete; + + // Define default move constructor + UnstructuredIrStreamReader(UnstructuredIrStreamReader&&) = default; + // Delete move assignment operator since it's also disabled in `clp::ir::LogEventDeserializer`. + auto operator=(UnstructuredIrStreamReader&&) -> UnstructuredIrStreamReader& = delete; + + [[nodiscard]] static auto create( + std::unique_ptr&& zstd_decompressor, + clp::Array&& data_array + ) -> std::unique_ptr; + + [[nodiscard]] auto get_num_events_buffered() const -> size_t override; + + [[nodiscard]] auto get_filtered_log_event_map() const -> FilteredLogEventMapTsType override; + + void filter_log_events(LogLevelFilterTsType const& log_level_filter) override; + + [[nodiscard]] auto deserialize_stream() -> size_t override; + + [[nodiscard]] auto decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const + -> DecodedResultsTsType override; + +private: + // Constructor + explicit UnstructuredIrStreamReader( + StreamReaderDataContext&& stream_reader_data_context + ); + + // Methods + [[nodiscard]] static auto create_data_context( + std::unique_ptr&& zstd_decompressor, + clp::Array&& data_buffer + ) -> StreamReaderDataContext; + + // Variables + std::vector> m_encoded_log_events; + std::unique_ptr> + m_stream_reader_data_context; + FilteredLogEventsMap m_filtered_log_event_map; + clp::TimestampPattern m_ts_pattern; +}; +} // namespace clp_ffi_js::ir + +#endif // CLP_FFI_JS_IR_UNSTRUCTUREDUnstructuredIrStreamReader_HPP From c81cd4b128c89ef0afe663f4e869d1796077d477 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Wed, 6 Nov 2024 16:40:09 +0000 Subject: [PATCH 28/40] cleanup --- CMakeLists.txt | 2 +- src/clp_ffi_js/ir/StreamReader.cpp | 116 ++++++++++-------- src/clp_ffi_js/ir/StreamReader.hpp | 28 ++--- .../ir/UnstructuredIrStreamReader.cpp | 8 +- .../ir/UnstructuredIrStreamReader.hpp | 26 ++-- 5 files changed, 88 insertions(+), 92 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b6d65a4..700c645f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,8 +113,8 @@ target_include_directories( target_include_directories(${CLP_FFI_JS_BIN_NAME} PRIVATE src/) set(CLP_FFI_JS_SRC_MAIN - src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp src/clp_ffi_js/ir/StreamReader.cpp + src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp ) set(CLP_FFI_JS_SRC_CLP_CORE diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index 8f07096e..f1506fc0 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -12,36 +13,43 @@ #include #include +#include +#include #include #include #include #include - -#include -#include - -#include -#include - -#include #include #include +#include +#include -namespace clp_ffi_js::ir { - +namespace { +using ClpFfiJsException = clp_ffi_js::ClpFfiJsException; +using IRErrorCode = clp::ffi::ir_stream::IRErrorCode; + +/** + * Rewinds the reader to start then validates the CLP IR data encoding type. + * @param reader + * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is + * unsupported. + */ auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void { reader.seek_from_begin(0); bool is_four_bytes_encoding{true}; if (auto const err{clp::ffi::ir_stream::get_encoding_type(reader, is_four_bytes_encoding)}; - clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != err) + IRErrorCode::IRErrorCode_Success != err) { throw ClpFfiJsException{ clp::ErrorCode::ErrorCode_MetadataCorrupted, __FILENAME__, __LINE__, - std::format("Failed to decode encoding type, err={}", clp::enum_to_underlying_type(err)) + std::format( + "Failed to decode encoding type: IR error code {}", + clp::enum_to_underlying_type(err) + ) }; } if (false == is_four_bytes_encoding) { @@ -54,21 +62,26 @@ auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> v } } +/** + * Gets the version of the IR stream. + * @param reader + * @throws ClpFfiJsException if the preamble couldn't be deserialized. + * @return The IR stream's version. + */ auto get_version(clp::ReaderInterface& reader) -> std::string { // Deserialize metadata bytes from preamble. clp::ffi::ir_stream::encoded_tag_t metadata_type{}; std::vector metadata_bytes; - auto const deserialize_preamble_result{ - clp::ffi::ir_stream::deserialize_preamble(reader, metadata_type, metadata_bytes) + auto const err{clp::ffi::ir_stream::deserialize_preamble(reader, metadata_type, metadata_bytes) }; - if (clp::ffi::ir_stream::IRErrorCode::IRErrorCode_Success != deserialize_preamble_result) { + if (IRErrorCode::IRErrorCode_Success != err) { throw ClpFfiJsException{ clp::ErrorCode::ErrorCode_Failure, __FILENAME__, __LINE__, std::format( - "Failed to deserialize preamble for version reading: {}", - clp::enum_to_underlying_type(deserialize_preamble_result) + "Failed to deserialize preamble: IR error code {}", + clp::enum_to_underlying_type(err) ) }; } @@ -91,10 +104,41 @@ auto get_version(clp::ReaderInterface& reader) -> std::string { }; } - SPDLOG_INFO("The version is {}", version); + SPDLOG_INFO("IR version is {}", version); return version; } +EMSCRIPTEN_BINDINGS(ClpStreamReader) { + // JS types used as inputs + emscripten::register_type("Uint8Array"); + emscripten::register_type("number[] | null"); + + // JS types used as outputs + emscripten::register_type( + "Array<[string, number, number, number]>" + ); + emscripten::register_type("number[] | null"); + emscripten::class_("ClpStreamReader") + .constructor( + &clp_ffi_js::ir::StreamReader::create, + emscripten::return_value_policy::take_ownership() + ) + .function( + "getNumEventsBuffered", + &clp_ffi_js::ir::StreamReader::get_num_events_buffered + ) + .function( + "getFilteredLogEventMap", + &clp_ffi_js::ir::StreamReader::get_filtered_log_event_map + ) + .function("filterLogEvents", &clp_ffi_js::ir::StreamReader::filter_log_events) + .function("deserializeStream", &clp_ffi_js::ir::StreamReader::deserialize_stream) + .function("decodeRange", &clp_ffi_js::ir::StreamReader::decode_range); +} +} // namespace + +namespace clp_ffi_js::ir { + auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr { auto const length{data_array["length"].as()}; SPDLOG_INFO("StreamReader::create: got buffer of length={}", length); @@ -119,47 +163,17 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< zstd_decompressor->seek_from_begin(reader_offset); if (std::ranges::find(cUnstructuredIrVersions, version) != cUnstructuredIrVersions.end()) { - return UnstructuredIrStreamReader::create( + return std::make_unique(UnstructuredIrStreamReader::create( std::move(zstd_decompressor), std::move(data_buffer) - ); + )); } throw ClpFfiJsException{ clp::ErrorCode::ErrorCode_Unsupported, __FILENAME__, __LINE__, - std::format("Unable to create reader for CLP stream with version {}.", version) + std::format("Unable to create reader for IR stream with version {}.", version) }; } } // namespace clp_ffi_js::ir - -namespace { -EMSCRIPTEN_BINDINGS(ClpStreamReader) { - // JS types used as outputs - emscripten::register_type("Uint8Array"); - emscripten::register_type( - "Array<[string, number, number, number]>" - ); - emscripten::register_type("number[] | null"); - - // JS types used as inputs - emscripten::register_type("number[] | null"); - emscripten::class_("ClpStreamReader") - .constructor( - &clp_ffi_js::ir::StreamReader::create, - emscripten::return_value_policy::take_ownership() - ) - .function( - "getNumEventsBuffered", - &clp_ffi_js::ir::StreamReader::get_num_events_buffered - ) - .function( - "getFilteredLogEventMap", - &clp_ffi_js::ir::StreamReader::get_filtered_log_event_map - ) - .function("filterLogEvents", &clp_ffi_js::ir::StreamReader::filter_log_events) - .function("deserializeStream", &clp_ffi_js::ir::StreamReader::deserialize_stream) - .function("decodeRange", &clp_ffi_js::ir::StreamReader::decode_range); -} -} // namespace diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index edb6790c..271ee5ef 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -1,5 +1,5 @@ -#ifndef CLP_FFI_JS_IR_STREAM_READER_HPP -#define CLP_FFI_JS_IR_STREAM_READER_HPP +#ifndef CLP_FFI_JS_IR_STREAMREADER_HPP +#define CLP_FFI_JS_IR_STREAMREADER_HPP #include #include @@ -11,31 +11,17 @@ namespace clp_ffi_js::ir { +// JS types used as inputs EMSCRIPTEN_DECLARE_VAL_TYPE(DataArrayTsType); +EMSCRIPTEN_DECLARE_VAL_TYPE(LogLevelFilterTsType); + +// JS types used as outputs EMSCRIPTEN_DECLARE_VAL_TYPE(DecodedResultsTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(FilteredLogEventMapTsType); -EMSCRIPTEN_DECLARE_VAL_TYPE(LogLevelFilterTsType); constexpr std::array cUnstructuredIrVersions = {"v0.0.2", "v0.0.1", "v0.0.0", "0.0.2", "0.0.1", "0.0.0"}; -/** -* Rewinds the reader to the beginning and validates the CLP IR data encoding type. -* @param reader -* @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is -* unsupported. -*/ -static auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void; - -/** -* Gets the version of the IR stream from the specified reader. -* @param reader -* @throws Propagates `rewind_reader_and_validate_encoding_type`'s exceptions. -* @throws ClpFfiJsException if the preamble couldn't be deserialized. -* @return The stream's version. -*/ -static auto get_version(clp::ReaderInterface& reader) -> std::string; - /** * Class to deserialize and decode Zstandard-compressed CLP IR streams as well as format decoded * log events. @@ -114,4 +100,4 @@ class StreamReader { explicit StreamReader() = default; }; } // namespace clp_ffi_js::ir -#endif // CLP_FFI_JS_IR_STREAM_READER_HPP +#endif // CLP_FFI_JS_IR_STREAMREADER_HPP diff --git a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp index 8fa7cebc..53c29710 100644 --- a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp +++ b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -39,8 +38,7 @@ using clp::ir::four_byte_encoded_variable_t; auto UnstructuredIrStreamReader::create( std::unique_ptr&& zstd_decompressor, clp::Array&& data_array -) -> std::unique_ptr { - +) -> UnstructuredIrStreamReader { auto result{ clp::ir::LogEventDeserializer::create(*zstd_decompressor) }; @@ -62,9 +60,7 @@ auto UnstructuredIrStreamReader::create( std::move(zstd_decompressor), std::move(result.value()) ); - return std::make_unique( - UnstructuredIrStreamReader(std::move(data_context)) - ); + return UnstructuredIrStreamReader(std::move(data_context)); } auto UnstructuredIrStreamReader::get_num_events_buffered() const -> size_t { diff --git a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp index 0fbce93c..a8b58b46 100644 --- a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp +++ b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp @@ -1,11 +1,10 @@ -#ifndef CLP_FFI_JS_IR_UNSTRUCTUREDUnstructuredIrStreamReader_HPP -#define CLP_FFI_JS_IR_UNSTRUCTUREDUnstructuredIrStreamReader_HPP +#ifndef CLP_FFI_JS_IR_UNSTRUCTUREDIRSTREAMREADER_HPP +#define CLP_FFI_JS_IR_UNSTRUCTUREDIRSTREAMREADER_HPP #include #include #include #include -#include #include #include @@ -30,8 +29,6 @@ using FilteredLogEventsMap = std::optional>; * decoded log events. */ class UnstructuredIrStreamReader : public StreamReader { - friend StreamReader; - public: // Destructor ~UnstructuredIrStreamReader() override = default; @@ -45,10 +42,19 @@ class UnstructuredIrStreamReader : public StreamReader { // Delete move assignment operator since it's also disabled in `clp::ir::LogEventDeserializer`. auto operator=(UnstructuredIrStreamReader&&) -> UnstructuredIrStreamReader& = delete; + /** + * First packages a `StreamReaderDataContext` using inputs and a unstructured IR deserializer, + * then creates a `UnstructuredIrStreamReader`. + * + * @param zstd_decompressor + * @param data_array An array containing a Zstandard-compressed IR stream. + * @return The created instance. + * @throw ClpFfiJsException if any error occurs. + */ [[nodiscard]] static auto create( std::unique_ptr&& zstd_decompressor, clp::Array&& data_array - ) -> std::unique_ptr; + ) -> UnstructuredIrStreamReader; [[nodiscard]] auto get_num_events_buffered() const -> size_t override; @@ -67,12 +73,6 @@ class UnstructuredIrStreamReader : public StreamReader { StreamReaderDataContext&& stream_reader_data_context ); - // Methods - [[nodiscard]] static auto create_data_context( - std::unique_ptr&& zstd_decompressor, - clp::Array&& data_buffer - ) -> StreamReaderDataContext; - // Variables std::vector> m_encoded_log_events; std::unique_ptr> @@ -82,4 +82,4 @@ class UnstructuredIrStreamReader : public StreamReader { }; } // namespace clp_ffi_js::ir -#endif // CLP_FFI_JS_IR_UNSTRUCTUREDUnstructuredIrStreamReader_HPP +#endif // CLP_FFI_JS_IR_UNSTRUCTUREDIRSTREAMREADER_HPP From 28d4250c094208ba59cdf6c0ac9a03b588137586 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Wed, 6 Nov 2024 17:01:52 +0000 Subject: [PATCH 29/40] fix seek issue --- src/clp_ffi_js/ir/StreamReader.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index f1506fc0..2519a541 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -153,21 +153,19 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< auto zstd_decompressor{std::make_unique()}; zstd_decompressor->open(data_buffer.data(), length); - size_t reader_offset = 0; - rewind_reader_and_validate_encoding_type(*zstd_decompressor); - reader_offset = zstd_decompressor->try_get_pos(reader_offset); - // Required to validate encoding type prior to getting version. + rewind_reader_and_validate_encoding_type(*zstd_decompressor); auto const version{get_version(*zstd_decompressor)}; - // Required that reader offset matches position after validation in order to decode log events. - zstd_decompressor->seek_from_begin(reader_offset); + // Required that reader offset matches position after validation in order to decode log events. + rewind_reader_and_validate_encoding_type(*zstd_decompressor); if (std::ranges::find(cUnstructuredIrVersions, version) != cUnstructuredIrVersions.end()) { return std::make_unique(UnstructuredIrStreamReader::create( std::move(zstd_decompressor), std::move(data_buffer) )); } + SPDLOG_INFO("did i get here 3"); throw ClpFfiJsException{ clp::ErrorCode::ErrorCode_Unsupported, From c5db9a6e19ea93265d24a3e949ac3064693bee7c Mon Sep 17 00:00:00 2001 From: davemarco <83603688+davemarco@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:25:45 -0500 Subject: [PATCH 30/40] Update src/clp_ffi_js/ir/StreamReader.cpp Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- src/clp_ffi_js/ir/StreamReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index 2519a541..8b4acb44 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -30,7 +30,7 @@ using ClpFfiJsException = clp_ffi_js::ClpFfiJsException; using IRErrorCode = clp::ffi::ir_stream::IRErrorCode; /** - * Rewinds the reader to start then validates the CLP IR data encoding type. + * Rewinds the reader to the beginning then validates the CLP IR data encoding type. * @param reader * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is * unsupported. From 4a83bce1fe8640ef848c38b945e40f2c298a985d Mon Sep 17 00:00:00 2001 From: davemarco <83603688+davemarco@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:26:06 -0500 Subject: [PATCH 31/40] Update src/clp_ffi_js/ir/StreamReader.hpp Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- src/clp_ffi_js/ir/StreamReader.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index 271ee5ef..a46d25fd 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -10,7 +10,6 @@ #include namespace clp_ffi_js::ir { - // JS types used as inputs EMSCRIPTEN_DECLARE_VAL_TYPE(DataArrayTsType); EMSCRIPTEN_DECLARE_VAL_TYPE(LogLevelFilterTsType); From de7a2f80675106a8be22773523884ce2cea11c92 Mon Sep 17 00:00:00 2001 From: davemarco <83603688+davemarco@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:26:28 -0500 Subject: [PATCH 32/40] Update src/clp_ffi_js/ir/StreamReader.hpp Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- src/clp_ffi_js/ir/StreamReader.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index a46d25fd..0336638e 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -52,7 +52,6 @@ class StreamReader { auto operator=(StreamReader&&) -> StreamReader& = delete; // Methods - /** * @return The number of events buffered. */ From 1b31f084c8fb0ede0f18e86dbedbd16a1e9a6996 Mon Sep 17 00:00:00 2001 From: davemarco <83603688+davemarco@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:28:28 -0500 Subject: [PATCH 33/40] Apply suggestions from code review Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- src/clp_ffi_js/ir/StreamReader.hpp | 1 + src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/clp_ffi_js/ir/StreamReader.hpp b/src/clp_ffi_js/ir/StreamReader.hpp index 0336638e..5f298674 100644 --- a/src/clp_ffi_js/ir/StreamReader.hpp +++ b/src/clp_ffi_js/ir/StreamReader.hpp @@ -98,4 +98,5 @@ class StreamReader { explicit StreamReader() = default; }; } // namespace clp_ffi_js::ir + #endif // CLP_FFI_JS_IR_STREAMREADER_HPP diff --git a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp index a8b58b46..1eca3360 100644 --- a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp +++ b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp @@ -43,11 +43,9 @@ class UnstructuredIrStreamReader : public StreamReader { auto operator=(UnstructuredIrStreamReader&&) -> UnstructuredIrStreamReader& = delete; /** - * First packages a `StreamReaderDataContext` using inputs and a unstructured IR deserializer, - * then creates a `UnstructuredIrStreamReader`. - * - * @param zstd_decompressor - * @param data_array An array containing a Zstandard-compressed IR stream. + * @param zstd_decompressor A decompressor for an IR stream, where the read head of the stream + * is just after the stream's encoding type. + * @param data_array The array backing `zstd_decompressor`. * @return The created instance. * @throw ClpFfiJsException if any error occurs. */ From 226ab3a25b34bb436e478c7a3f7ec2db6ea5eb91 Mon Sep 17 00:00:00 2001 From: davemarco <83603688+davemarco@users.noreply.github.com> Date: Wed, 6 Nov 2024 15:09:37 -0500 Subject: [PATCH 34/40] Update src/clp_ffi_js/ir/StreamReader.cpp Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- src/clp_ffi_js/ir/StreamReader.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index 8b4acb44..a0d6f87c 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -138,7 +138,6 @@ EMSCRIPTEN_BINDINGS(ClpStreamReader) { } // namespace namespace clp_ffi_js::ir { - auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr { auto const length{data_array["length"].as()}; SPDLOG_INFO("StreamReader::create: got buffer of length={}", length); From fa4debd1041d5de585be9a1853214ba0009f0a36 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Wed, 6 Nov 2024 19:33:00 +0000 Subject: [PATCH 35/40] change to pass by value --- src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp | 2 +- src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp index 53c29710..242d8472 100644 --- a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp +++ b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.cpp @@ -37,7 +37,7 @@ using clp::ir::four_byte_encoded_variable_t; auto UnstructuredIrStreamReader::create( std::unique_ptr&& zstd_decompressor, - clp::Array&& data_array + clp::Array data_array ) -> UnstructuredIrStreamReader { auto result{ clp::ir::LogEventDeserializer::create(*zstd_decompressor) diff --git a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp index 1eca3360..b5312b0b 100644 --- a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp +++ b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp @@ -51,7 +51,7 @@ class UnstructuredIrStreamReader : public StreamReader { */ [[nodiscard]] static auto create( std::unique_ptr&& zstd_decompressor, - clp::Array&& data_array + clp::Array data_array ) -> UnstructuredIrStreamReader; [[nodiscard]] auto get_num_events_buffered() const -> size_t override; From 4108398fd2f5a7631726c2781aa296321fc8c8b1 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Wed, 6 Nov 2024 20:13:01 +0000 Subject: [PATCH 36/40] kirk changes --- src/clp_ffi_js/.clang-format | 2 +- src/clp_ffi_js/ir/StreamReader.cpp | 58 +++++++++++++++++------------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/clp_ffi_js/.clang-format b/src/clp_ffi_js/.clang-format index 00a39854..7b8cbd47 100644 --- a/src/clp_ffi_js/.clang-format +++ b/src/clp_ffi_js/.clang-format @@ -7,7 +7,7 @@ IncludeCategories: Priority: 4 # Library headers. Update when adding new libraries. # NOTE: clang-format retains leading white-space on a line in violation of the YAML spec. - - Regex: "<(emscripten|fmt|spdlog)" + - Regex: "<(emscripten|fmt|spdlog|json)" Priority: 3 - Regex: "^<(clp)" Priority: 3 diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index a0d6f87c..d2b365a2 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -20,6 +19,7 @@ #include #include #include +#include #include #include @@ -29,12 +29,23 @@ namespace { using ClpFfiJsException = clp_ffi_js::ClpFfiJsException; using IRErrorCode = clp::ffi::ir_stream::IRErrorCode; +// Function declarations /** * Rewinds the reader to the beginning then validates the CLP IR data encoding type. * @param reader * @throws ClpFfiJsException if the encoding type couldn't be decoded or the encoding type is * unsupported. */ +auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void; + +/** + * Gets the version of the IR stream. + * @param reader + * @throws ClpFfiJsException if the preamble couldn't be deserialized. + * @return The IR stream's version. + */ +auto get_version(clp::ReaderInterface& reader) -> std::string; + auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> void { reader.seek_from_begin(0); @@ -62,12 +73,6 @@ auto rewind_reader_and_validate_encoding_type(clp::ReaderInterface& reader) -> v } } -/** - * Gets the version of the IR stream. - * @param reader - * @throws ClpFfiJsException if the preamble couldn't be deserialized. - * @return The IR stream's version. - */ auto get_version(clp::ReaderInterface& reader) -> std::string { // Deserialize metadata bytes from preamble. clp::ffi::ir_stream::encoded_tag_t metadata_type{}; @@ -152,25 +157,30 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< auto zstd_decompressor{std::make_unique()}; zstd_decompressor->open(data_buffer.data(), length); - // Required to validate encoding type prior to getting version. rewind_reader_and_validate_encoding_type(*zstd_decompressor); + // Validate the stream's version + auto pos = zstd_decompressor->get_pos(); auto const version{get_version(*zstd_decompressor)}; - - // Required that reader offset matches position after validation in order to decode log events. - rewind_reader_and_validate_encoding_type(*zstd_decompressor); - if (std::ranges::find(cUnstructuredIrVersions, version) != cUnstructuredIrVersions.end()) { - return std::make_unique(UnstructuredIrStreamReader::create( - std::move(zstd_decompressor), - std::move(data_buffer) - )); + if (std::ranges::find(cUnstructuredIrVersions, version) == cUnstructuredIrVersions.end()) { + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_Unsupported, + __FILENAME__, + __LINE__, + std::format("Unable to create reader for IR stream with version {}.", version) + }; } - SPDLOG_INFO("did i get here 3"); - - throw ClpFfiJsException{ - clp::ErrorCode::ErrorCode_Unsupported, - __FILENAME__, - __LINE__, - std::format("Unable to create reader for IR stream with version {}.", version) - }; + try { + zstd_decompressor->seek_from_begin(pos); + } catch (ZstdDecompressor::OperationFailed& e) { + throw ClpFfiJsException{ + clp::ErrorCode::ErrorCode_Failure, + __FILENAME__, + __LINE__, + std::format("Unable to rewind zstd decompressor: {}", e.what()) + }; + } + return std::make_unique( + UnstructuredIrStreamReader::create(std::move(zstd_decompressor), std::move(data_buffer)) + ); } } // namespace clp_ffi_js::ir From c7a8fbfd4236d5c061720742d16cac66ddefe2d4 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Wed, 6 Nov 2024 23:39:21 +0000 Subject: [PATCH 37/40] change submodule --- tools/yscope-dev-utils | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/yscope-dev-utils b/tools/yscope-dev-utils index 159768c7..ad576e43 160000 --- a/tools/yscope-dev-utils +++ b/tools/yscope-dev-utils @@ -1 +1 @@ -Subproject commit 159768c7d171595ed2cba17b758c10043a2efe96 +Subproject commit ad576e43c1a43d7a6afde79fc9c3c952b7bf28bd From bfea301fe8adf55b9ff6a9a76c93d32ae14790b3 Mon Sep 17 00:00:00 2001 From: davemarco <83603688+davemarco@users.noreply.github.com> Date: Wed, 6 Nov 2024 18:45:40 -0500 Subject: [PATCH 38/40] Apply suggestions from code review Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com> --- src/clp_ffi_js/.clang-format | 2 +- src/clp_ffi_js/ir/StreamReader.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/clp_ffi_js/.clang-format b/src/clp_ffi_js/.clang-format index 7b8cbd47..b8345f82 100644 --- a/src/clp_ffi_js/.clang-format +++ b/src/clp_ffi_js/.clang-format @@ -7,7 +7,7 @@ IncludeCategories: Priority: 4 # Library headers. Update when adding new libraries. # NOTE: clang-format retains leading white-space on a line in violation of the YAML spec. - - Regex: "<(emscripten|fmt|spdlog|json)" + - Regex: "<(emscripten|fmt|json|spdlog)" Priority: 3 - Regex: "^<(clp)" Priority: 3 diff --git a/src/clp_ffi_js/ir/StreamReader.cpp b/src/clp_ffi_js/ir/StreamReader.cpp index d2b365a2..c6b097cb 100644 --- a/src/clp_ffi_js/ir/StreamReader.cpp +++ b/src/clp_ffi_js/ir/StreamReader.cpp @@ -158,6 +158,7 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< zstd_decompressor->open(data_buffer.data(), length); rewind_reader_and_validate_encoding_type(*zstd_decompressor); + // Validate the stream's version auto pos = zstd_decompressor->get_pos(); auto const version{get_version(*zstd_decompressor)}; @@ -179,6 +180,7 @@ auto StreamReader::create(DataArrayTsType const& data_array) -> std::unique_ptr< std::format("Unable to rewind zstd decompressor: {}", e.what()) }; } + return std::make_unique( UnstructuredIrStreamReader::create(std::move(zstd_decompressor), std::move(data_buffer)) ); From 72bdf6efa2e3347f925604081a877808e4860f39 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Wed, 6 Nov 2024 23:58:20 +0000 Subject: [PATCH 39/40] revert submodule change --- src/submodules/clp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/submodules/clp b/src/submodules/clp index 9f6a6ced..e1f3f2ab 160000 --- a/src/submodules/clp +++ b/src/submodules/clp @@ -1 +1 @@ -Subproject commit 9f6a6ced4da504f6ba3c131efa26fd5b30c6f533 +Subproject commit e1f3f2abe3473324b19d66e22c182ec3ac0d408f From 119de6c2b0091aeee048504be05f7426af6c2590 Mon Sep 17 00:00:00 2001 From: Dave Marco Date: Thu, 7 Nov 2024 00:26:08 +0000 Subject: [PATCH 40/40] use see --- src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp index b5312b0b..91b78eba 100644 --- a/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp +++ b/src/clp_ffi_js/ir/UnstructuredIrStreamReader.hpp @@ -60,6 +60,13 @@ class UnstructuredIrStreamReader : public StreamReader { void filter_log_events(LogLevelFilterTsType const& log_level_filter) override; + /** + * @see StreamReader::deserialize_stream + * + * After the stream has been exhausted, it will be deallocated. + * + * @return @see StreamReader::deserialize_stream + */ [[nodiscard]] auto deserialize_stream() -> size_t override; [[nodiscard]] auto decode_range(size_t begin_idx, size_t end_idx, bool use_filter) const