Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Checks: >
-*,
bugprone-*,
-bugprone-easily-swappable-parameters,
-bugprone-invalid-enum-default-initialization,
clang-analyzer-*,
-clang-analyzer-optin.cplusplus.VirtualCall,
clang-diagnostic-*,
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## 0.55.0 - 2026-04-28

### Enhancements
- Improved `DbnDecoder` throughput on current-version data and `AsIs` workloads by
caching whether the upgrade policy-version combination requires upgrading, skipping
the per-record `DecodeRecordCompat` dispatch on the fast path
- Made `detail::Buffer` shifts explicit to avoid redundant moves during record decoding
- Added new publisher values for Cboe Titanium Cboe Global Indices Feed
- Added `Year` to `SplitDuration` enum for yearly historical batch job submissions
- Upgraded default cpp-httplib version to 0.43.1
- Upgraded default nlohmann/json version to 3.12.0

## 0.54.0 - 2026-04-21

### Enhancements
Expand Down
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24..4.2)

project(
databento
VERSION 0.54.0
VERSION 0.55.0
LANGUAGES CXX
DESCRIPTION "Official Databento client library"
)
Expand Down Expand Up @@ -152,7 +152,7 @@ if(${PROJECT_NAME_UPPERCASE}_USE_EXTERNAL_JSON)
find_package(nlohmann_json REQUIRED)
endif()
else()
set(json_version 3.11.3)
set(json_version 3.12.0)
# Required to correctly install nlohmann_json
set(JSON_Install ON)
FetchContent_Declare(
Expand All @@ -178,7 +178,7 @@ if(${PROJECT_NAME_UPPERCASE}_USE_EXTERNAL_HTTPLIB)
find_package(httplib REQUIRED)
endif()
else()
set(httplib_version 0.37.2)
set(httplib_version 0.43.1)
FetchContent_Declare(
httplib
URL https://github.com/yhirose/cpp-httplib/archive/refs/tags/v${httplib_version}.tar.gz
Expand Down
4 changes: 4 additions & 0 deletions include/databento/dbn_decoder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class DbnDecoder {
VersionUpgradePolicy upgrade_policy, bool ts_out,
std::array<std::byte, kMaxRecordLen>* compat_buffer,
Record rec);
// Returns whether a record from `version`-formatted data requires runtime
// upgrade dispatch under `upgrade_policy`.
static bool NeedsUpgrade(VersionUpgradePolicy upgrade_policy, std::uint8_t version);

// Should be called exactly once.
Metadata DecodeMetadata();
Expand All @@ -61,6 +64,7 @@ class DbnDecoder {
ILogReceiver* log_receiver_;
std::uint8_t version_{};
VersionUpgradePolicy upgrade_policy_;
bool needs_upgrade_{true};
bool ts_out_{};
std::unique_ptr<IReadable> input_;
detail::Buffer buffer_{};
Expand Down
16 changes: 8 additions & 8 deletions include/databento/detail/buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,7 @@ class Buffer : public IReadable, public IWritable {
std::byte* ReadEnd() { return write_pos_; }
const std::byte* ReadBegin() const { return read_pos_; }
const std::byte* ReadEnd() const { return write_pos_; }
// Indicate how many bytes were read
void Consume(std::size_t length) {
read_pos_ += length;
if (static_cast<std::size_t>(read_pos_ - buf_.get()) > (Capacity() / 2)) {
Shift();
}
}
void ConsumeNoShift(std::size_t length) { read_pos_ += length; }
void Consume(std::size_t length) { read_pos_ += length; }
std::size_t ReadCapacity() const {
return static_cast<std::size_t>(write_pos_ - read_pos_);
}
Expand All @@ -65,6 +58,13 @@ class Buffer : public IReadable, public IWritable {
}
void Reserve(std::size_t capacity);
void Shift();
// Shifts unread data to offset 0 if writable space is less than `needed`,
// reclaiming the consumed prefix. Does not grow the buffer.
void ShiftForSpace(std::size_t needed) {
if (WriteCapacity() < needed && read_pos_ != buf_.get()) {
Shift();
}
}

friend std::ostream& operator<<(std::ostream& stream, const Buffer& buffer);

Expand Down
1 change: 1 addition & 0 deletions include/databento/detail/dbn_buffer_decoder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class DbnBufferDecoder {
alignas(RecordHeader) std::array<std::byte, kMaxRecordLen> compat_buffer_{};
std::uint8_t input_version_{};
bool ts_out_{};
bool needs_upgrade_{true};
DecoderState state_{DecoderState::Init};
};
} // namespace databento::detail
2 changes: 1 addition & 1 deletion include/databento/detail/http_client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class HttpClient {
httplib::Result&& res) const;
void CheckWarnings(const httplib::Response& response) const;

static const httplib::Headers kHeaders;
static const httplib::Headers& BaseHeaders();

ILogReceiver* log_receiver_;
httplib::Client client_;
Expand Down
1 change: 1 addition & 0 deletions include/databento/enums.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum class SplitDuration : std::uint8_t {
Day = 0,
Week,
Month,
Year,
None,
};

Expand Down
6 changes: 6 additions & 0 deletions include/databento/publishers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ enum class Venue : std::uint16_t {
Mxto = 54,
// IEX Options LLC
Iexo = 55,
// Cboe Global Indices Feed
Cgif = 56,
};

// A source of data.
Expand Down Expand Up @@ -203,6 +205,8 @@ enum class Dataset : std::uint16_t {
XcbfPitch = 40,
// Blue Ocean ATS MEMOIR Depth
OceaMemoir = 41,
// Cboe Titanium Cboe Global Indices Feed
CgifTitanium = 42,
};

// A specific Venue from a specific data source.
Expand Down Expand Up @@ -425,6 +429,8 @@ enum class Publisher : std::uint16_t {
OpraPillarMxto = 108,
// OPRA - IEX Options LLC
OpraPillarIexo = 109,
// Cboe Global Indices Feed
CgifTitaniumCgif = 110,
};

// Get a Publisher's Venue.
Expand Down
5 changes: 3 additions & 2 deletions include/databento/symbology.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <ostream>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>

Expand All @@ -28,10 +29,10 @@ struct SymbologyResolution {
//
// Throws InvalidArgumentError if symbols is empty or the iterator range is
// empty.
std::string JoinSymbolStrings(const std::string& method_name,
std::string JoinSymbolStrings(std::string_view method_name,
std::vector<std::string>::const_iterator symbols_begin,
std::vector<std::string>::const_iterator symbols_end);
std::string JoinSymbolStrings(const std::string& method_name,
std::string JoinSymbolStrings(std::string_view method_name,
const std::vector<std::string>& symbols);
std::string ToString(const SymbologyResolution& sym_res);
std::ostream& operator<<(std::ostream& stream, const SymbologyResolution& sym_res);
Expand Down
2 changes: 1 addition & 1 deletion pkg/PKGBUILD
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Maintainer: Databento <support@databento.com>
_pkgname=databento-cpp
pkgname=databento-cpp-git
pkgver=0.54.0
pkgver=0.55.0
pkgrel=1
pkgdesc="Official C++ client for Databento"
arch=('any')
Expand Down
26 changes: 20 additions & 6 deletions src/dbn_decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ databento::Metadata DbnDecoder::DecodeMetadata() {
buffer_.ReadBegin(), kMetadataPreludeSize);
buffer_.Consume(kMetadataPreludeSize);
version_ = version;
needs_upgrade_ = NeedsUpgrade(upgrade_policy_, version_);
buffer_.Reserve(size);
input_->ReadExact(buffer_.WriteBegin(), size);
buffer_.Fill(size);
Expand Down Expand Up @@ -273,6 +274,19 @@ databento::Record DbnDecoder::DecodeRecordCompat(
return rec;
}

bool DbnDecoder::NeedsUpgrade(VersionUpgradePolicy upgrade_policy,
std::uint8_t version) {
switch (upgrade_policy) {
case VersionUpgradePolicy::UpgradeToV2:
return version < 2;
case VersionUpgradePolicy::UpgradeToV3:
return version < 3;
case VersionUpgradePolicy::AsIs:
default:
return false;
}
}

// assumes DecodeMetadata has been called
const databento::Record* DbnDecoder::DecodeRecord() {
// need some unread unread_bytes
Expand All @@ -293,16 +307,16 @@ const databento::Record* DbnDecoder::DecodeRecord() {
}
}
current_record_ = Record{BufferRecordHeader()};
buffer_.ConsumeNoShift(current_record_.Size());
current_record_ = DbnDecoder::DecodeRecordCompat(version_, upgrade_policy_, ts_out_,
&compat_buffer_, current_record_);
buffer_.Consume(current_record_.Size());
if (needs_upgrade_) {
current_record_ = DbnDecoder::DecodeRecordCompat(version_, upgrade_policy_, ts_out_,
&compat_buffer_, current_record_);
}
return &current_record_;
}

size_t DbnDecoder::FillBuffer() {
if (buffer_.WriteCapacity() < kMaxRecordLen) {
buffer_.Shift();
}
buffer_.ShiftForSpace(kMaxRecordLen);
const auto fill_size =
input_->ReadSome(buffer_.WriteBegin(), buffer_.WriteCapacity());
buffer_.Fill(fill_size);
Expand Down
8 changes: 3 additions & 5 deletions src/detail/buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ size_t Buffer::Write(const char* data, std::size_t length) {
return Write(reinterpret_cast<const std::byte*>(data), length);
}
size_t Buffer::Write(const std::byte* data, std::size_t length) {
if (length > WriteCapacity()) {
Shift();
}
ShiftForSpace(length);
const auto write_size = std::min(WriteCapacity(), length);
std::copy(data, data + write_size, WriteBegin());
Fill(write_size);
Expand All @@ -28,8 +26,8 @@ void Buffer::WriteAll(const char* data, std::size_t length) {
void Buffer::WriteAll(const std::byte* data, std::size_t length) {
if (length > Capacity() - ReadCapacity()) {
Reserve(ReadCapacity() + length);
} else if (length >= WriteCapacity()) {
Shift();
} else {
ShiftForSpace(length);
}
std::copy(data, data + length, WriteBegin());
write_pos_ += length;
Expand Down
9 changes: 7 additions & 2 deletions src/detail/dbn_buffer_decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ using databento::detail::DbnBufferDecoder;
databento::KeepGoing DbnBufferDecoder::Process(const char* data, std::size_t length) {
zstd_buffer_->WriteAll(data, length);
while (true) {
dbn_buffer_.ShiftForSpace(kMaxRecordLen);
const auto read_size =
zstd_stream_.ReadSome(dbn_buffer_.WriteBegin(), dbn_buffer_.WriteCapacity());
dbn_buffer_.Fill(read_size);
Expand All @@ -24,6 +25,7 @@ databento::KeepGoing DbnBufferDecoder::Process(const char* data, std::size_t len
std::tie(input_version_, bytes_needed_) =
DbnDecoder::DecodeMetadataVersionAndSize(dbn_buffer_.ReadBegin(),
dbn_buffer_.ReadCapacity());
needs_upgrade_ = DbnDecoder::NeedsUpgrade(upgrade_policy_, input_version_);
dbn_buffer_.Consume(kMetadataPreludeSize);
dbn_buffer_.Reserve(bytes_needed_);
state_ = DecoderState::Metadata;
Expand Down Expand Up @@ -55,8 +57,10 @@ databento::KeepGoing DbnBufferDecoder::Process(const char* data, std::size_t len
if (dbn_buffer_.ReadCapacity() < bytes_needed_) {
break;
}
record = DbnDecoder::DecodeRecordCompat(input_version_, upgrade_policy_,
ts_out_, &compat_buffer_, record);
if (needs_upgrade_) {
record = DbnDecoder::DecodeRecordCompat(input_version_, upgrade_policy_,
ts_out_, &compat_buffer_, record);
}
if (record_callback_(record) == KeepGoing::Stop) {
return KeepGoing::Stop;
}
Expand All @@ -77,6 +81,7 @@ std::ostream& operator<<(std::ostream& stream, const DbnBufferDecoder& buffer) {
.AddField("bytes_needed_", buffer.bytes_needed_)
.AddField("input_version_", buffer.input_version_)
.AddField("ts_out_", buffer.ts_out_)
.AddField("needs_upgrade_", buffer.needs_upgrade_)
.AddField("state_", buffer.state_)
.Finish();
}
Expand Down
16 changes: 10 additions & 6 deletions src/detail/http_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@
using databento::detail::HttpClient;

constexpr std::chrono::seconds kTimeout{100};
const httplib::Headers HttpClient::kHeaders{
{"accept", "application/json"},
{"user-agent", kUserAgent},
};

const httplib::Headers& HttpClient::BaseHeaders() {
static const httplib::Headers kHeaders{
{"accept", "application/json"},
{"user-agent", kUserAgent},
};
return kHeaders;
}

HttpClient::HttpClient(databento::ILogReceiver* log_receiver, const std::string& key,
const std::string& gateway)
: log_receiver_{log_receiver}, client_{gateway} {
auto headers = HttpClient::kHeaders;
auto headers = HttpClient::BaseHeaders();
headers.insert(httplib::make_basic_authentication_header(key, ""));
client_.set_default_headers(headers);
client_.set_basic_auth(key, "");
Expand All @@ -34,7 +38,7 @@ HttpClient::HttpClient(databento::ILogReceiver* log_receiver, const std::string&
HttpClient::HttpClient(databento::ILogReceiver* log_receiver, const std::string& key,
const std::string& gateway, std::uint16_t port)
: log_receiver_{log_receiver}, client_{gateway, port} {
auto headers = HttpClient::kHeaders;
auto headers = HttpClient::BaseHeaders();
headers.insert(httplib::make_basic_authentication_header(key, ""));
client_.set_default_headers(headers);
client_.set_basic_auth(key, "");
Expand Down
6 changes: 6 additions & 0 deletions src/enums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ const char* ToString(SplitDuration duration_interval) {
case SplitDuration::Month: {
return "month";
}
case SplitDuration::Year: {
return "year";
}
case SplitDuration::None: {
return "none";
}
Expand Down Expand Up @@ -979,6 +982,9 @@ SplitDuration FromString(const std::string& str) {
if (str == "month") {
return SplitDuration::Month;
}
if (str == "year") {
return SplitDuration::Year;
}
if (str == "none") {
return SplitDuration::None;
}
Expand Down
Loading
Loading