Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add support for the 8-byte long timestamp delta encoding #166

Merged
merged 10 commits into from
Sep 29, 2023
43 changes: 40 additions & 3 deletions components/core/src/ffi/ir_stream/decoding_methods.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "decoding_methods.hpp"

#include <regex>

#include "byteswap.hpp"
#include "protocol_constants.hpp"

Expand Down Expand Up @@ -251,6 +253,12 @@ parse_timestamp(ReaderInterface& reader, encoded_tag_t encoded_tag, epoch_time_m
return IRErrorCode_Incomplete_IR;
}
ts = ts_delta;
} else if (cProtocol::Payload::TimestampDeltaLong == encoded_tag) {
int64_t ts_delta;
if (false == decode_int(reader, ts_delta)) {
return IRErrorCode_Incomplete_IR;
}
ts = ts_delta;
} else {
return IRErrorCode_Corrupted_IR;
}
Expand All @@ -277,9 +285,8 @@ generic_decode_next_message(ReaderInterface& reader, string& message, epoch_time
message.append(value, begin_pos, length);
};

auto encoded_int_handler = [&](encoded_variable_t value) {
message.append(decode_integer_var(value));
};
auto encoded_int_handler
= [&](encoded_variable_t value) { message.append(decode_integer_var(value)); };

auto encoded_float_handler = [&](encoded_variable_t encoded_float) {
message.append(decode_float_var(encoded_float));
Expand Down Expand Up @@ -458,6 +465,36 @@ IRErrorCode decode_preamble(
return IRErrorCode_Success;
}

IRProtocolErrorCode validate_protocol_version(std::string_view protocol_version) {
if ("v0.0.0" == protocol_version) {
// This version is hardcoded to support the oldest IR protocol version.
// When this version is no longer supported, this branch should be
// removed.
return IRProtocolErrorCode_Supported;
}
std::regex const protocol_version_regex{cProtocol::Metadata::VersionRegex};
if (false
== std::regex_match(
protocol_version.begin(),
protocol_version.end(),
protocol_version_regex
))
{
return IRProtocolErrorCode_Invalid;
}
std::string_view current_build_protocol_version{cProtocol::Metadata::VersionValue};
auto get_major_version{[](std::string_view version) {
return version.substr(0, version.find('.'));
}};
if (current_build_protocol_version < protocol_version) {
return IRProtocolErrorCode_Too_New;
}
if (get_major_version(current_build_protocol_version) > get_major_version(protocol_version)) {
return IRProtocolErrorCode_Too_Old;
}
return IRProtocolErrorCode_Supported;
}

namespace four_byte_encoding {
IRErrorCode decode_next_message(
ReaderInterface& reader,
Expand Down
21 changes: 21 additions & 0 deletions components/core/src/ffi/ir_stream/decoding_methods.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ typedef enum {
IRErrorCode_Incomplete_IR,
} IRErrorCode;

typedef enum {
IRProtocolErrorCode_Supported,
IRProtocolErrorCode_Too_Old,
IRProtocolErrorCode_Too_New,
IRProtocolErrorCode_Invalid,
} IRProtocolErrorCode;

class DecodingException : public TraceableException {
public:
// Constructors
Expand Down Expand Up @@ -142,6 +149,20 @@ IRErrorCode decode_preamble(
std::vector<int8_t>& metadata
);

/**
* Validates whether the given protocol version can be supported by the current
* build.
* @param protocol_version
* @return IRProtocolErrorCode_Supported if the protocol version is supported.
* @return IRProtocolErrorCode_Too_Old if the protocol version is no longer
* supported by the current build version.
LinZhihao-723 marked this conversation as resolved.
Show resolved Hide resolved
* @return IRProtocolErrorCode_Too_New if the protocol version is newer than the
* build version.
LinZhihao-723 marked this conversation as resolved.
Show resolved Hide resolved
* @return IRProtocolErrorCode_Invalid if the protocol version does not follow
* the SemVer specification.
*/
IRProtocolErrorCode validate_protocol_version(std::string_view protocol_version);

namespace eight_byte_encoding {
/**
* Decodes the next message for the eight-byte encoding IR stream.
Expand Down
10 changes: 5 additions & 5 deletions components/core/src/ffi/ir_stream/encoding_methods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,7 @@ static void add_base_metadata_fields(
* @param logtype
* @return true
*/
static bool append_constant_to_logtype(
string_view constant,
string& logtype
);
static bool append_constant_to_logtype(string_view constant, string& logtype);

/**
* A functor for encoding dictionary variables in a message
Expand Down Expand Up @@ -308,8 +305,11 @@ namespace four_byte_encoding {
} else if (INT32_MIN <= timestamp_delta && timestamp_delta <= INT32_MAX) {
ir_buf.push_back(cProtocol::Payload::TimestampDeltaInt);
encode_int(static_cast<int32_t>(timestamp_delta), ir_buf);
} else if (INT64_MIN <= timestamp_delta && timestamp_delta <= INT64_MAX) {
ir_buf.push_back(cProtocol::Payload::TimestampDeltaLong);
encode_int(static_cast<int64_t>(timestamp_delta), ir_buf);
} else {
// Delta exceeds maximum representable by an int (24.86 days)
// Delta exceeds maximum representable by a 64-bit int
return false;
}

Expand Down
10 changes: 9 additions & 1 deletion components/core/src/ffi/ir_stream/protocol_constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ namespace Metadata {
constexpr int8_t LengthUShort = 0x12;

constexpr char VersionKey[] = "VERSION";
constexpr char VersionValue[] = "v0.0.0";
constexpr char VersionValue[] = "0.0.1";

// The following regex can be used to validate a Semantic Versioning string.
// The source of the regex can be found here: https://semver.org/
constexpr char VersionRegex[] = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)"
"(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)"
"(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?"
"(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$";

constexpr char TimestampPatternKey[] = "TIMESTAMP_PATTERN";
constexpr char TimestampPatternSyntaxKey[] = "TIMESTAMP_PATTERN_SYNTAX";
Expand All @@ -39,6 +46,7 @@ namespace Payload {
constexpr int8_t TimestampDeltaByte = 0x31;
constexpr int8_t TimestampDeltaShort = 0x32;
constexpr int8_t TimestampDeltaInt = 0x33;
constexpr int8_t TimestampDeltaLong = 0x34;
} // namespace Payload

constexpr int8_t FourByteEncodingMagicNumber[]
Expand Down
4 changes: 2 additions & 2 deletions components/core/src/ir/LogEventDeserializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ auto LogEventDeserializer<encoded_variable_t>::create(ReaderInterface& reader)
return std::errc::protocol_error;
}
auto metadata_version = version_iter->get_ref<nlohmann::json::string_t&>();
if (static_cast<char const*>(ffi::ir_stream::cProtocol::Metadata::VersionValue)
!= metadata_version)
if (ffi::ir_stream::IRProtocolErrorCode_Supported
!= ffi::ir_stream::validate_protocol_version(metadata_version))
{
return std::errc::protocol_not_supported;
}
Expand Down
Loading
Loading