From 09d0e6bfd510f628bb5608279908104b891bd58a Mon Sep 17 00:00:00 2001 From: Oscar Le Dauphin Date: Mon, 15 Jun 2026 20:32:08 +0200 Subject: [PATCH 1/8] use libdatadog trace filter implementation --- Cargo.lock | 1 + components-rs/agent_info.rs | 15 +- components-rs/common.h | 15 -- components-rs/datadog.h | 7 +- components-rs/trace_filter.rs | 289 +++++++--------------------------- libdatadog | 2 +- tracer/trace_filter.c | 21 +-- 7 files changed, 72 insertions(+), 278 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72bf6449d2a..7ac8c71076e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2919,6 +2919,7 @@ dependencies = [ "libdd-shared-runtime", "libdd-telemetry", "libdd-tinybytes", + "libdd-trace-normalization", "libdd-trace-obfuscation", "libdd-trace-protobuf", "libdd-trace-stats", diff --git a/components-rs/agent_info.rs b/components-rs/agent_info.rs index ad3dd9cdff8..b157922e3a2 100644 --- a/components-rs/agent_info.rs +++ b/components-rs/agent_info.rs @@ -18,12 +18,15 @@ use std::ffi::CString; fn info_to_concentrator_config(info: &AgentInfoStruct) { apply_concentrator_config( info.peer_tags.as_deref().unwrap_or(&[]).to_owned(), - info.span_kinds_stats_computed.as_deref().unwrap_or(&[]).to_owned(), - info.filter_tags.as_ref().and_then(|f| f.require.as_deref()).unwrap_or(&[]).to_owned(), - info.filter_tags.as_ref().and_then(|f| f.reject.as_deref()).unwrap_or(&[]).to_owned(), - info.filter_tags_regex.as_ref().and_then(|f| f.require.as_deref()).unwrap_or(&[]).to_owned(), - info.filter_tags_regex.as_ref().and_then(|f| f.reject.as_deref()).unwrap_or(&[]).to_owned(), - info.ignore_resources.as_deref().unwrap_or(&[]).to_owned(), + info.span_kinds_stats_computed + .as_deref() + .unwrap_or(&[]) + .to_owned(), + info.filter_tags.require.to_owned(), + info.filter_tags.reject.to_owned(), + info.filter_tags_regex.require.to_owned(), + info.filter_tags_regex.reject.to_owned(), + info.ignore_resources.to_owned(), info.client_drop_p0s.unwrap_or(false), info.version.as_deref(), ); diff --git a/components-rs/common.h b/components-rs/common.h index 5c0b9606b79..9a148cb5d8b 100644 --- a/components-rs/common.h +++ b/components-rs/common.h @@ -785,21 +785,6 @@ typedef const char *(*ddog_RootTagLookupFn)(const void *ctx, uintptr_t key_len, uintptr_t *out_len); -/** - * Per-entry callback passed to `RootMetaIterFn`. Return `false` to stop iteration early. - */ -typedef bool (*ddog_MetaEntryCb)(void *iter_ctx, - const char *key, - uintptr_t key_len, - const char *val, - uintptr_t val_len); - -/** - * Slow-path meta iterator. `NULL` when no regex-key filter entries are present. - * Iterates all string meta entries, calling `cb` for each; stops when `cb` returns `false`. - */ -typedef void (*ddog_RootMetaIterFn)(const void *ctx, void *iter_ctx, ddog_MetaEntryCb cb); - /** * A 128-bit (16 byte) buffer containing the UUID. * diff --git a/components-rs/datadog.h b/components-rs/datadog.h index 2a75fb13b9b..bb08a554b10 100644 --- a/components-rs/datadog.h +++ b/components-rs/datadog.h @@ -407,16 +407,13 @@ bool ddog_sidecar_telemetry_are_endpoints_collected(ddog_ShmCacheMap *cache, * no stats). Filters are evaluated against the root span — the decision applies uniformly * to all spans of the trace. * - * * **Common case**: `filter_tags` and literal-key `filter_tags_regex` entries — one O(1) + * * **When configured**: `filter_tags` and `filter_tags_regex` entries — one * `lookup_fn` call per filter entry. - * * **Rare case**: `filter_tags_regex` entries with regex key patterns — `iter_fn` is invoked - * to scan all meta entries for those filters. Pass `NULL` when not needed. * * **Fast path**: returns `true` immediately when no filters are configured. */ bool ddog_check_stats_trace_filter(ddog_CharSlice resource, const void *root_span, - ddog_RootTagLookupFn lookup_fn, - ddog_RootMetaIterFn iter_fn); + ddog_RootTagLookupFn lookup_fn); void ddog_init_span_func(void (*free_func)(ddog_OwnedZendString), void (*addref_func)(struct _zend_string*), diff --git a/components-rs/trace_filter.rs b/components-rs/trace_filter.rs index 2fefd0543b6..264217c0638 100644 --- a/components-rs/trace_filter.rs +++ b/components-rs/trace_filter.rs @@ -14,121 +14,49 @@ //! case). `ddog_check_stats_trace_filter` returns `true` immediately in that case. use libdd_common_ffi::slice::{AsBytes, CharSlice}; -use regex::Regex; +use libdd_trace_utils::trace_filter::{Span as TraceFilterSpan, TraceFilterer}; use std::ffi::{c_char, c_void}; use std::sync::{LazyLock, RwLock}; -use tracing::info; - -/// An exact-match tag filter: `"key"` (key-presence only) or `"key:value"`. -struct TagFilter { - key: String, - value: Option, -} - -/// A `filter_tags_regex` entry whose key is a plain literal — direct O(1) lookup. -struct TagRegexFilter { - key: String, - value: Option, -} - -/// A `filter_tags_regex` entry whose key is itself a regex pattern — requires meta iteration. -struct TagRegexKeyFilter { - key_re: Regex, - value: Option, -} - -/// Compiled trace filter rules, ready for fast evaluation. -pub(crate) struct TraceFilterConfig { - filter_tags_require: Vec, - filter_tags_reject: Vec, - /// Literal-key regex filters: O(1) lookup per entry via the C lookup callback. - filter_tags_regex_require: Vec, - filter_tags_regex_reject: Vec, - /// Regex-key filters (rare): require meta iteration via the C iterator callback. - filter_tags_regex_key_require: Vec, - filter_tags_regex_key_reject: Vec, - ignore_resources: Vec, -} - -fn parse_tag_filter(s: &str) -> TagFilter { - match s.find(':') { - Some(i) => TagFilter { key: s[..i].to_owned(), value: Some(s[i + 1..].to_owned()) }, - None => TagFilter { key: s.to_owned(), value: None }, - } -} - -/// Compile a regex anchored to the full string. -fn compile_anchored(pattern: &str) -> Option { - Regex::new(&format!("^(?:{pattern})$")).ok() -} - -/// Returns `true` when `key` contains no regex metacharacters and can be used for a direct -/// O(1) lookup. `.` is intentionally treated as a literal (not a wildcard) in key patterns. -fn is_literal_key(key: &str) -> bool { - !key.contains(|c: char| matches!(c, '*' | '+' | '?' | '[' | ']' | '(' | ')' | '{' | '}' | '^' | '$' | '|' | '\\')) -} - -/// Compile all `filter_tags_regex` entries, splitting into literal-key (fast) and -/// regex-key (slow) lists based on whether the key portion contains metacharacters. -fn compile_regex_filters(entries: &[String]) -> (Vec, Vec) { - let mut literal = Vec::new(); - let mut regex_key = Vec::new(); - for s in entries { - let (key_str, value_str) = match s.find(':') { - Some(i) => (&s[..i], Some(&s[i + 1..])), - None => (s.as_str(), None), - }; - let value = value_str.and_then(|v| compile_anchored(v)); - if is_literal_key(key_str) { - literal.push(TagRegexFilter { key: key_str.to_owned(), value }); - } else if let Some(key_re) = compile_anchored(key_str) { - regex_key.push(TagRegexKeyFilter { key_re, value }); - } else { - info!("'{key_str}' regex tag filter is not a valid regex"); - } - } - (literal, regex_key) -} /// Compile all filter arguments into a `TraceFilterConfig`, or return `None` when all lists /// are empty (no filtering needed). pub(crate) fn compile_trace_filter( - tags_require: &[String], - tags_reject: &[String], - regex_require: &[String], - regex_reject: &[String], + filter_tags_require: &[String], + filter_tags_reject: &[String], + filter_tags_regex_require: &[String], + filter_tags_regex_reject: &[String], ignore_resources: &[String], -) -> Option { - if tags_require.is_empty() - && tags_reject.is_empty() - && regex_require.is_empty() - && regex_reject.is_empty() - && ignore_resources.is_empty() +) -> Option { + if [ + filter_tags_require, + filter_tags_reject, + filter_tags_regex_require, + filter_tags_regex_reject, + ignore_resources, + ] + .iter() + .all(|v| v.is_empty()) { - return None; + None + } else { + Some(TraceFilterer::new( + filter_tags_require, + filter_tags_reject, + filter_tags_regex_require, + filter_tags_regex_reject, + ignore_resources, + )) } - let (regex_require_literal, regex_require_key) = compile_regex_filters(regex_require); - let (regex_reject_literal, regex_reject_key) = compile_regex_filters(regex_reject); - Some(TraceFilterConfig { - filter_tags_require: tags_require.iter().map(|s| parse_tag_filter(s)).collect(), - filter_tags_reject: tags_reject.iter().map(|s| parse_tag_filter(s)).collect(), - filter_tags_regex_require: regex_require_literal, - filter_tags_regex_reject: regex_reject_literal, - filter_tags_regex_key_require: regex_require_key, - filter_tags_regex_key_reject: regex_reject_key, - ignore_resources: ignore_resources.iter().filter_map(|s| compile_anchored(s)).collect(), - }) } /// Currently active compiled trace filter. `None` when no filters are configured. -static TRACE_FILTER: LazyLock>> = - LazyLock::new(|| RwLock::new(None)); +static TRACE_FILTER: LazyLock>> = LazyLock::new(|| RwLock::new(None)); /// Replace the active trace filter with a freshly compiled one. /// /// Called from `apply_concentrator_config` in `stats.rs` whenever the agent /info SHM /// is updated. -pub(crate) fn set_trace_filter(compiled: Option) { +pub(crate) fn set_trace_filter(compiled: Option) { *TRACE_FILTER.write().unwrap() = compiled; } @@ -140,76 +68,37 @@ pub type RootTagLookupFn = unsafe extern "C" fn( out_len: *mut usize, ) -> *const c_char; -/// Per-entry callback passed to `RootMetaIterFn`. Return `false` to stop iteration early. -pub type MetaEntryCb = unsafe extern "C" fn( - iter_ctx: *mut c_void, - key: *const c_char, - key_len: usize, - val: *const c_char, - val_len: usize, -) -> bool; - -/// Slow-path meta iterator. `NULL` when no regex-key filter entries are present. -/// Iterates all string meta entries, calling `cb` for each; stops when `cb` returns `false`. -pub type RootMetaIterFn = Option< - unsafe extern "C" fn(ctx: *const c_void, iter_ctx: *mut c_void, cb: MetaEntryCb), ->; - -#[inline] -unsafe fn lookup_tag<'a>( - lookup: RootTagLookupFn, - ctx: *const c_void, - key: &str, -) -> Option<&'a str> { - let mut vlen: usize = 0; - let vptr = lookup(ctx, key.as_ptr() as *const c_char, key.len(), &mut vlen); - if vptr.is_null() { - None - } else { - Some(std::str::from_utf8_unchecked(std::slice::from_raw_parts( - vptr as *const u8, - vlen, - ))) - } +struct Span<'a> { + resource_str: &'a str, + root_span: *const c_void, + lookup_fn: RootTagLookupFn, } -/// State threaded through the opaque `iter_ctx` pointer during regex-key meta scans. -struct IterState<'a> { - key_re: &'a Regex, - value: &'a Option, - found: bool, -} +impl<'a> TraceFilterSpan<'a> for Span<'a> { + fn resource_normalized(&'a self) -> &'a str { + // FIXME: normalization: if resource is empty, name should be used instead + self.resource_str + } -/// Trampoline called by C for each meta entry. Sets `found = true` and stops on a match. -unsafe extern "C" fn meta_entry_cb( - iter_ctx: *mut c_void, - key: *const c_char, - klen: usize, - val: *const c_char, - vlen: usize, -) -> bool { - let state = &mut *(iter_ctx as *mut IterState); - let k = std::str::from_utf8_unchecked(std::slice::from_raw_parts(key as *const u8, klen)); - if state.key_re.is_match(k) { - let v = std::str::from_utf8_unchecked(std::slice::from_raw_parts(val as *const u8, vlen)); - if state.value.as_ref().map_or(true, |re| re.is_match(v)) { - state.found = true; - return false; // stop iteration + fn get_meta(&'a self, key: &str) -> Option<&'a str> { + unsafe { + let mut vlen: usize = 0; + let vptr = (self.lookup_fn)( + self.root_span, + key.as_ptr() as *const c_char, + key.len(), + &mut vlen, + ); + if vptr.is_null() { + None + } else { + Some(std::str::from_utf8_unchecked(std::slice::from_raw_parts( + vptr as *const u8, + vlen, + ))) + } } } - true // continue -} - -/// Use the iterator to check whether any meta entry matches a `TagRegexKeyFilter`. -#[inline] -unsafe fn regex_key_matches( - iter: unsafe extern "C" fn(*const c_void, *mut c_void, MetaEntryCb), - ctx: *const c_void, - filter: &TagRegexKeyFilter, -) -> bool { - let mut state = IterState { key_re: &filter.key_re, value: &filter.value, found: false }; - iter(ctx, &mut state as *mut IterState as *mut c_void, meta_entry_cb); - state.found } /// Check whether the trace rooted at `resource` / `root_span` passes all configured trace @@ -219,17 +108,14 @@ unsafe fn regex_key_matches( /// no stats). Filters are evaluated against the root span — the decision applies uniformly /// to all spans of the trace. /// -/// * **Common case**: `filter_tags` and literal-key `filter_tags_regex` entries — one O(1) +/// * **When configured**: `filter_tags` and `filter_tags_regex` entries — one /// `lookup_fn` call per filter entry. -/// * **Rare case**: `filter_tags_regex` entries with regex key patterns — `iter_fn` is invoked -/// to scan all meta entries for those filters. Pass `NULL` when not needed. /// * **Fast path**: returns `true` immediately when no filters are configured. #[no_mangle] pub unsafe extern "C" fn ddog_check_stats_trace_filter( resource: CharSlice<'_>, root_span: *const c_void, lookup_fn: RootTagLookupFn, - iter_fn: RootMetaIterFn, ) -> bool { let guard = TRACE_FILTER.read().unwrap(); // Fast path: None means no filters configured (overwhelmingly common). @@ -237,68 +123,9 @@ pub unsafe extern "C" fn ddog_check_stats_trace_filter( return true; }; - let resource_str = resource.try_to_utf8().unwrap_or(""); - - // 1. ignore_resources: reject if root resource matches any pattern. - for re in &f.ignore_resources { - if re.is_match(resource_str) { - return false; - } - } - // 2. filter_tags.reject: reject if the root span has a matching tag. - for filter in &f.filter_tags_reject { - if let Some(val) = lookup_tag(lookup_fn, root_span, &filter.key) { - if filter.value.as_deref().map_or(true, |v| v == val) { - return false; - } - } - } - // 3a. filter_tags_regex.reject (literal key): reject if value matches. - for filter in &f.filter_tags_regex_reject { - if let Some(val) = lookup_tag(lookup_fn, root_span, &filter.key) { - if filter.value.as_ref().map_or(true, |re| re.is_match(val)) { - return false; - } - } - } - // 3b. filter_tags_regex.reject (regex key): slow path — iterate all meta. - if let Some(iter) = iter_fn { - for filter in &f.filter_tags_regex_key_reject { - if regex_key_matches(iter, root_span, filter) { - return false; - } - } - } - // 4. filter_tags.require: reject unless every required tag is present and matches. - for filter in &f.filter_tags_require { - match lookup_tag(lookup_fn, root_span, &filter.key) { - None => return false, - Some(val) => { - if filter.value.as_deref().is_some_and(|v| v != val) { - return false; - } - } - } - } - // 5a. filter_tags_regex.require (literal key): reject unless matched. - for filter in &f.filter_tags_regex_require { - match lookup_tag(lookup_fn, root_span, &filter.key) { - None => return false, - Some(val) => { - if filter.value.as_ref().is_some_and(|re| !re.is_match(val)) { - return false; - } - } - } - } - // 5b. filter_tags_regex.require (regex key): slow path — every required pattern must match. - if let Some(iter) = iter_fn { - for filter in &f.filter_tags_regex_key_require { - if !regex_key_matches(iter, root_span, filter) { - return false; - } - } - } - - true + !f.should_drop(&Span { + resource_str: resource.try_to_utf8().unwrap_or(""), + root_span, + lookup_fn, + }) } diff --git a/libdatadog b/libdatadog index c79d783f79f..cc7156b6b5f 160000 --- a/libdatadog +++ b/libdatadog @@ -1 +1 @@ -Subproject commit c79d783f79f4a2d1e637906f3323600c6e2b5b17 +Subproject commit cc7156b6b5f47964b967c2f719c4cb22597dd221 diff --git a/tracer/trace_filter.c b/tracer/trace_filter.c index 3c34dd1b059..61dcd6116c7 100644 --- a/tracer/trace_filter.c +++ b/tracer/trace_filter.c @@ -77,30 +77,11 @@ static const char *ddtrace_root_tag_value(const void *ctx, const char *key, uint return NULL; } -// Slow-path iterator for regex-key filter entries: walks every string meta entry. -static void ddtrace_meta_iter(const void *ctx, void *iter_ctx, - bool (*cb)(void *, const char *, uintptr_t, const char *, uintptr_t)) { - ddtrace_span_data *root = (ddtrace_span_data *)ctx; - zend_array *meta = ddtrace_property_array(&root->property_meta); - if (!meta) { - return; - } - zend_string *key; - zval *val; - ZEND_HASH_FOREACH_STR_KEY_VAL(meta, key, val) { - if (key && Z_TYPE_P(val) == IS_STRING) { - if (!cb(iter_ctx, ZSTR_VAL(key), ZSTR_LEN(key), Z_STRVAL_P(val), Z_STRLEN_P(val))) { - break; - } - } - } ZEND_HASH_FOREACH_END(); -} - bool ddtrace_trace_passes_filter(ddtrace_span_data *span) { zval *root_resource_zv = &span->root->property_resource; ZVAL_DEREF(root_resource_zv); ddog_CharSlice resource = Z_TYPE_P(root_resource_zv) == IS_STRING ? dd_zend_string_to_CharSlice(Z_STR_P(root_resource_zv)) : DDOG_CHARSLICE_C(""); - return ddog_check_stats_trace_filter(resource, span, ddtrace_root_tag_value, ddtrace_meta_iter); + return ddog_check_stats_trace_filter(resource, span, ddtrace_root_tag_value); } From 0e9c66f89f99add30db69bbaab83ec5123500a6d Mon Sep 17 00:00:00 2001 From: Oscar Le Dauphin <90446228+Eldolfin@users.noreply.github.com> Date: Mon, 15 Jun 2026 21:30:33 +0200 Subject: [PATCH 2/8] Doc comment fix Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- components-rs/trace_filter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components-rs/trace_filter.rs b/components-rs/trace_filter.rs index 264217c0638..465a42219b9 100644 --- a/components-rs/trace_filter.rs +++ b/components-rs/trace_filter.rs @@ -18,7 +18,7 @@ use libdd_trace_utils::trace_filter::{Span as TraceFilterSpan, TraceFilterer}; use std::ffi::{c_char, c_void}; use std::sync::{LazyLock, RwLock}; -/// Compile all filter arguments into a `TraceFilterConfig`, or return `None` when all lists +/// Compile all filter arguments into a `TraceFilterer`, or return `None` when all lists /// are empty (no filtering needed). pub(crate) fn compile_trace_filter( filter_tags_require: &[String], From c3abf03916a56f93b9779c02dfedac7c12cc724e Mon Sep 17 00:00:00 2001 From: Oscar Le Dauphin Date: Tue, 16 Jun 2026 12:05:14 +0200 Subject: [PATCH 3/8] feat: normalize resource before passing it to rust --- components-rs/trace_filter.rs | 2 +- .../client_side_stats_trace_filters.phpt | 7 +++++++ tracer/trace_filter.c | 9 +++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/components-rs/trace_filter.rs b/components-rs/trace_filter.rs index 465a42219b9..304a5be569e 100644 --- a/components-rs/trace_filter.rs +++ b/components-rs/trace_filter.rs @@ -76,7 +76,7 @@ struct Span<'a> { impl<'a> TraceFilterSpan<'a> for Span<'a> { fn resource_normalized(&'a self) -> &'a str { - // FIXME: normalization: if resource is empty, name should be used instead + // Resource has been normalized on the C side before calling ddog_check_stats_trace_filter self.resource_str } diff --git a/tests/ext/request-replayer/client_side_stats_trace_filters.phpt b/tests/ext/request-replayer/client_side_stats_trace_filters.phpt index 25f2b3b1261..a20f412cfa6 100644 --- a/tests/ext/request-replayer/client_side_stats_trace_filters.phpt +++ b/tests/ext/request-replayer/client_side_stats_trace_filters.phpt @@ -114,6 +114,13 @@ makeSpan('op.blocked.regex_require', 'GET /other4', [ 'http.method' => 'DELETE', ]); +// 7. BLOCKED by ignore_resources — resource is empty so name "GET /healthcheck" is used instead and matches the pattern (as per normalization rules). +makeSpan('GET /healthcheck', '', [ + 'filter_required' => 'yes', + 'http.method' => 'GET', +]); + + dd_trace_internal_fn('synchronous_flush'); // Capture ALL trace requests from the second flush before consuming them. diff --git a/tracer/trace_filter.c b/tracer/trace_filter.c index 61dcd6116c7..4479a2da530 100644 --- a/tracer/trace_filter.c +++ b/tracer/trace_filter.c @@ -83,5 +83,14 @@ bool ddtrace_trace_passes_filter(ddtrace_span_data *span) { ddog_CharSlice resource = Z_TYPE_P(root_resource_zv) == IS_STRING ? dd_zend_string_to_CharSlice(Z_STR_P(root_resource_zv)) : DDOG_CHARSLICE_C(""); + // Temp normalize resource: if it's empty use the name instead + if (resource.len == 0) { + zval* root_name_zv = &span->root->property_name; + ZVAL_DEREF(root_name_zv); + resource = + Z_TYPE_P(root_name_zv) == IS_STRING + ? dd_zend_string_to_CharSlice(Z_STR_P(root_name_zv)) + : DDOG_CHARSLICE_C(""); + } return ddog_check_stats_trace_filter(resource, span, ddtrace_root_tag_value); } From 7081d19a9cbe80c7b5878ae411d05e8be54fe6e1 Mon Sep 17 00:00:00 2001 From: Oscar Le Dauphin Date: Tue, 16 Jun 2026 12:36:43 +0200 Subject: [PATCH 4/8] fix(tests/crashtracker): removed frame_count field --- tests/ext/crashtracker_segfault.phpt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/ext/crashtracker_segfault.phpt b/tests/ext/crashtracker_segfault.phpt index f8ad77aa9ef..0171930d6eb 100644 --- a/tests/ext/crashtracker_segfault.phpt +++ b/tests/ext/crashtracker_segfault.phpt @@ -99,8 +99,7 @@ $rr->waitForRequest(function ($request) { "line": 1 } ] - }, - "frame_count": %d + } }, %A "incomplete": false, From d3645788198f82c179be38a046695a446adaf7f6 Mon Sep 17 00:00:00 2001 From: Oscar Le Dauphin Date: Tue, 16 Jun 2026 20:46:19 +0200 Subject: [PATCH 5/8] fix: point libdatadog to main again --- libdatadog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdatadog b/libdatadog index cc7156b6b5f..952c2ef75cd 160000 --- a/libdatadog +++ b/libdatadog @@ -1 +1 @@ -Subproject commit cc7156b6b5f47964b967c2f719c4cb22597dd221 +Subproject commit 952c2ef75cdf7b2895d7152100ea61c12ccf4439 From 4e6734aa7a2e2b3921312da0451e2aead9f633ed Mon Sep 17 00:00:00 2001 From: Oscar Le Dauphin Date: Tue, 16 Jun 2026 20:48:04 +0200 Subject: [PATCH 6/8] test: update rc_process_tags expected output --- tests/ext/remote_config/rc_process_tags.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ext/remote_config/rc_process_tags.phpt b/tests/ext/remote_config/rc_process_tags.phpt index 3fcc880d882..9c3d156afe8 100644 --- a/tests/ext/remote_config/rc_process_tags.phpt +++ b/tests/ext/remote_config/rc_process_tags.phpt @@ -62,7 +62,7 @@ reset_request_replayer(); ?> --EXPECTF-- entrypoint.basedir:remote_config -entrypoint.name:rc_process_tags +entrypoint.name:rc_process_tags.skip entrypoint.type:script entrypoint.workdir:%s runtime.sapi:cli From 63cceb012570687b0a38c7c9b1f90a81a575062d Mon Sep 17 00:00:00 2001 From: Oscar Le Dauphin Date: Wed, 17 Jun 2026 11:49:03 +0200 Subject: [PATCH 7/8] Revert "test: update rc_process_tags expected output" This reverts commit 765bf5cbd4f1db2aa5d70ac500679e2390d78315. --- tests/ext/remote_config/rc_process_tags.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ext/remote_config/rc_process_tags.phpt b/tests/ext/remote_config/rc_process_tags.phpt index 9c3d156afe8..3fcc880d882 100644 --- a/tests/ext/remote_config/rc_process_tags.phpt +++ b/tests/ext/remote_config/rc_process_tags.phpt @@ -62,7 +62,7 @@ reset_request_replayer(); ?> --EXPECTF-- entrypoint.basedir:remote_config -entrypoint.name:rc_process_tags.skip +entrypoint.name:rc_process_tags entrypoint.type:script entrypoint.workdir:%s runtime.sapi:cli From 2854817d4b017bac7998d5a5c217cbcced8d9e3b Mon Sep 17 00:00:00 2001 From: Oscar Le Dauphin Date: Wed, 17 Jun 2026 13:08:39 +0200 Subject: [PATCH 8/8] feat: cargo lock --- Cargo.lock | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 7ac8c71076e..c20cc9837f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2941,9 +2941,12 @@ dependencies = [ name = "libdd-ddsketch" version = "1.0.1" dependencies = [ + "criterion", "prost", "prost-build", "protoc-bin-vendored", + "rand 0.8.5", + "rand_chacha 0.3.1", ] [[package]] @@ -3274,6 +3277,7 @@ dependencies = [ "serde", "serde_json", "tempfile", + "thin-vec", "tokio", "tracing", "urlencoding", @@ -5629,6 +5633,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "thin-vec" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0f7e269b48f0a7dd0146680fa24b50cc67fc0373f086a5b2f99bd084639b482" + [[package]] name = "thiserror" version = "1.0.69"