diff --git a/libs/common/include/launchdarkly/config/shared/builders/events_builder.hpp b/libs/common/include/launchdarkly/config/shared/builders/events_builder.hpp index ac5fd7510..ef81f7313 100644 --- a/libs/common/include/launchdarkly/config/shared/builders/events_builder.hpp +++ b/libs/common/include/launchdarkly/config/shared/builders/events_builder.hpp @@ -107,6 +107,20 @@ class EventsBuilder { */ EventsBuilder& PrivateAttribute(AttributeReference attribute); + /** + * @brief Specifies the number of unique context keys that can be remembered + * by the index event generation logic before needing to evict keys from + * memory in LRU order. + * + * After reaching capacity, it's possible + * that a previously-indexed context may cause generation of a redundant + * index event. + * + * @param capacity Maximum unique context keys to remember. + * @return Reference to this builder. + */ + EventsBuilder& ContextKeysCapacity(std::size_t capacity); + /** * Builds Events configuration, if the configuration is valid. * @return Events config, or error. diff --git a/libs/common/include/launchdarkly/config/shared/built/events.hpp b/libs/common/include/launchdarkly/config/shared/built/events.hpp index 2b3e76c35..d18b8eb08 100644 --- a/libs/common/include/launchdarkly/config/shared/built/events.hpp +++ b/libs/common/include/launchdarkly/config/shared/built/events.hpp @@ -93,8 +93,8 @@ class Events final { [[nodiscard]] std::size_t FlushWorkers() const; /** - * Max number of unique context keys to hold in LRU cache used for context - * deduplication when generating index events. + * Number of unique contexts to remember when deduplicating index + * events. * @return Max, or std::nullopt if not applicable. */ [[nodiscard]] std::optional ContextKeysCacheCapacity() const; diff --git a/libs/common/src/config/events_builder.cpp b/libs/common/src/config/events_builder.cpp index 2f67b8c14..321907d4d 100644 --- a/libs/common/src/config/events_builder.cpp +++ b/libs/common/src/config/events_builder.cpp @@ -25,6 +25,13 @@ EventsBuilder& EventsBuilder::Capacity(std::size_t capacity) { return *this; } +template +EventsBuilder& EventsBuilder::ContextKeysCapacity( + std::size_t capacity) { + config_.context_keys_cache_capacity_ = capacity; + return *this; +} + template EventsBuilder& EventsBuilder::FlushInterval( std::chrono::milliseconds interval) { diff --git a/libs/server-sdk/include/launchdarkly/server_side/bindings/c/config/builder.h b/libs/server-sdk/include/launchdarkly/server_side/bindings/c/config/builder.h index d64d89235..0de2226be 100644 --- a/libs/server-sdk/include/launchdarkly/server_side/bindings/c/config/builder.h +++ b/libs/server-sdk/include/launchdarkly/server_side/bindings/c/config/builder.h @@ -107,6 +107,22 @@ LDServerConfigBuilder_Offline(LDServerConfigBuilder b, bool offline); LD_EXPORT(void) LDServerConfigBuilder_Events_Enabled(LDServerConfigBuilder b, bool enabled); +/** + * Specifies the number of unique context keys that can be remembered + * by the index event generation logic before needing to evict keys from + * memory in LRU order. + * + * After reaching capacity, it's possible + * that a previously-indexed context may cause generation of a redundant + * index event. + * @param b Server config builder. Must not be NULL. + * @param context_keys_capacity Maximum unique context keys to remember. The default + * is 1000. + */ +LD_EXPORT(void) +LDServerConfigBuilder_Events_ContextKeysCapacity(LDServerConfigBuilder b, + size_t context_keys_capacity); + /** * Sets the capacity of the event processor. When more events are generated * within the processor's flush interval than this value, events will be diff --git a/libs/server-sdk/src/bindings/c/builder.cpp b/libs/server-sdk/src/bindings/c/builder.cpp index 9576b1cc6..6dfbfbb4b 100644 --- a/libs/server-sdk/src/bindings/c/builder.cpp +++ b/libs/server-sdk/src/bindings/c/builder.cpp @@ -140,6 +140,14 @@ LDServerConfigBuilder_Events_Capacity(LDServerConfigBuilder b, TO_BUILDER(b)->Events().Capacity(capacity); } +LD_EXPORT(void) +LDServerConfigBuilder_Events_ContextKeysCapacity(LDServerConfigBuilder b, + size_t context_keys_capacity) { + LD_ASSERT_NOT_NULL(b); + + TO_BUILDER(b)->Events().ContextKeysCapacity(context_keys_capacity); +} + LD_EXPORT(void) LDServerConfigBuilder_Events_FlushIntervalMs(LDServerConfigBuilder b, unsigned int milliseconds) { @@ -225,7 +233,7 @@ LD_EXPORT(LDServerDataSourcePollBuilder) LDServerDataSourcePollBuilder_New() { LD_EXPORT(void) LDServerDataSourcePollBuilder_IntervalS(LDServerDataSourcePollBuilder b, - unsigned int seconds) { + unsigned int seconds) { LD_ASSERT_NOT_NULL(b); TO_POLL_BUILDER(b)->PollInterval(std::chrono::seconds{seconds}); diff --git a/libs/server-sdk/tests/server_c_bindings_test.cpp b/libs/server-sdk/tests/server_c_bindings_test.cpp index 382adb280..338095fb6 100644 --- a/libs/server-sdk/tests/server_c_bindings_test.cpp +++ b/libs/server-sdk/tests/server_c_bindings_test.cpp @@ -9,6 +9,7 @@ #include #include +#include TEST(ClientBindings, MinimalInstantiation) { LDServerConfigBuilder cfg_builder = LDServerConfigBuilder_New("sdk-123"); @@ -186,3 +187,29 @@ TEST(ClientBindings, DoubleVariationPassesThroughDefault) { LDServerSDK_Free(sdk); LDContext_Free(context); } + +TEST(ClientBindings, CanSetEventConfigurationSuccessfully) { + LDServerConfigBuilder cfg_builder = LDServerConfigBuilder_New("sdk-123"); + + LDServerConfigBuilder_Events_Enabled(cfg_builder, false); + LDServerConfigBuilder_Events_Capacity(cfg_builder, 100); + LDServerConfigBuilder_Events_ContextKeysCapacity(cfg_builder, 100); + LDServerConfigBuilder_Events_PrivateAttribute(cfg_builder, "email"); + LDServerConfigBuilder_Events_AllAttributesPrivate(cfg_builder, true); + + LDServerConfig config; + LDStatus status = LDServerConfigBuilder_Build(cfg_builder, &config); + ASSERT_TRUE(LDStatus_Ok(status)); + + launchdarkly::server_side::Config const* c = + reinterpret_cast(config); + + ASSERT_EQ(c->Events().Capacity(), 100); + ASSERT_EQ(c->Events().ContextKeysCacheCapacity(), 100); + ASSERT_EQ(c->Events().PrivateAttributes(), + launchdarkly::AttributeReference::SetType{"email"}); + ASSERT_TRUE(c->Events().AllAttributesPrivate()); + ASSERT_FALSE(c->Events().Enabled()); + + LDServerConfig_Free(config); +}