Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e044023
[SDK-2070] feat: add CachedFlagStore to DataSourceBuildInputs for cac…
aaron-zeisler Apr 6, 2026
596bc97
[SDK-2070] feat: implement FDv2CacheInitializer and CacheInitializerB…
aaron-zeisler Apr 6, 2026
563ec22
[SDK-2070] feat: wire cache initializer into the default mode table
aaron-zeisler Apr 6, 2026
dbe5c65
[SDK-2070] Added comments where cache initialization is redundant
aaron-zeisler Apr 8, 2026
70bd195
[SDK-2070] refactor: skip redundant cache load in FDv2 path
aaron-zeisler Apr 8, 2026
f856058
[SDK-2070] refactor: replace CachedFlagStore with ReadOnlyPerEnvironm…
aaron-zeisler Apr 10, 2026
24c962f
[SDK-2070] fix: return ChangeSetType.None on cache miss instead of in…
aaron-zeisler Apr 10, 2026
e1617fe
Merge branch 'main' into aaronz/SDK-2070/cache-initializer
tanderson-ld Apr 10, 2026
7b5ed27
[SDK-2070] fix: defer init completion to synchronizers and treat cach…
aaron-zeisler Apr 13, 2026
6aeea41
[SDK-2070] Addressing code review comments
aaron-zeisler Apr 13, 2026
b8a50de
[SDK-2070] Merge branch 'aaronz/SDK-2070/cache-initializer' of github…
aaron-zeisler Apr 13, 2026
3f0066b
[SDK-2070] Run FDv2CacheInitializer synchronously to eliminate execut…
aaron-zeisler Apr 13, 2026
8f5353a
[SDK-2070] Add isRequiredBeforeStartup() marker to Initializer interface
aaron-zeisler Apr 14, 2026
4e9746d
[SDK-2070] Build initializers eagerly in FDv2DataSourceBuilder
aaron-zeisler Apr 14, 2026
b9b1851
[SDK-2070] Update SourceManager to accept pre-built initializers with…
aaron-zeisler Apr 14, 2026
4a82402
[SDK-2070] Add two-pass initializer execution in FDv2DataSource
aaron-zeisler Apr 14, 2026
e8caa9f
[SDK-2070] Add tests for pre-startup initializer execution
aaron-zeisler Apr 14, 2026
41ac382
[SDK-2070] Addressing code review: remove synchronizer awareness from…
aaron-zeisler Apr 15, 2026
9e51057
[SDK-2070] Addressing code review: use DataSourceBuildInputsInternal …
aaron-zeisler Apr 15, 2026
3050faf
Merge branch 'main' into aaronz/SDK-2070/cache-initializer
aaron-zeisler Apr 17, 2026
2bdaf5a
[SDK-2070] Merge branch 'aaronz/SDK-2070/cache-initializer-guarantee-…
aaron-zeisler Apr 17, 2026
5e9fa17
[SDK-2070] Split cache initializers from general initializers in FDv2…
aaron-zeisler Apr 17, 2026
9fbd135
[SDK-2070] chore: remove unused imports from branch-edited files
aaron-zeisler Apr 17, 2026
fc931a8
[SDK-2070] Addressing code review comments
aaron-zeisler Apr 20, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ public PersistentDataStoreWrapper.PerEnvironmentData getPerEnvironmentData() {
return throwExceptionIfNull(perEnvironmentData);
}

@Nullable
public PersistentDataStoreWrapper.PerEnvironmentData getPerEnvironmentDataIfAvailable() {
return perEnvironmentData;
}

@Nullable
public TransactionalDataStore getTransactionalDataStore() {
return transactionalDataStore;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import androidx.annotation.NonNull;

import com.launchdarkly.sdk.android.subsystems.CachedFlagStore;
import com.launchdarkly.sdk.android.subsystems.ClientContext;
import com.launchdarkly.sdk.android.subsystems.ComponentConfigurer;
import com.launchdarkly.sdk.android.subsystems.DataSource;
Expand Down Expand Up @@ -149,18 +150,30 @@ public void close() {
}

private DataSourceBuildInputs makeInputs(ClientContext clientContext) {
TransactionalDataStore store = ClientContextImpl.get(clientContext).getTransactionalDataStore();
ClientContextImpl impl = ClientContextImpl.get(clientContext);
TransactionalDataStore store = impl.getTransactionalDataStore();
SelectorSource selectorSource = store != null
? new SelectorSourceFacade(store)
: () -> com.launchdarkly.sdk.fdv2.Selector.EMPTY;

PersistentDataStoreWrapper.PerEnvironmentData envData = impl.getPerEnvironmentDataIfAvailable();
CachedFlagStore cachedFlagStore = envData != null
? context -> {
String hashedId = LDUtil.urlSafeBase64HashedContextId(context);
EnvironmentData stored = envData.getContextData(hashedId);
return stored != null ? stored.getAll() : null;
}
: null;

return new DataSourceBuildInputs(
clientContext.getEvaluationContext(),
clientContext.getServiceEndpoints(),
clientContext.getHttp(),
clientContext.isEvaluationReasons(),
selectorSource,
sharedExecutor,
ClientContextImpl.get(clientContext).getPlatformState().getCacheDir(),
impl.getPlatformState().getCacheDir(),
cachedFlagStore,
clientContext.getBaseLogger()
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.launchdarkly.sdk.android.subsystems;

import androidx.annotation.Nullable;

import com.launchdarkly.sdk.LDContext;
import com.launchdarkly.sdk.android.DataModel;

import java.util.Map;

/**
* Provides read access to cached flag data for a specific evaluation context.
* <p>
* This interface bridges the persistence layer with FDv2 data source builders,
* allowing the cache initializer to load stored flags without depending on
* package-private types.
*/
public interface CachedFlagStore {
Comment thread
aaron-zeisler marked this conversation as resolved.
Outdated
/**
* Returns the cached flag data for the given context, or null if no
* cached data exists.
*
* @param context the evaluation context to look up
* @return the cached flags, or null on cache miss
*/
@Nullable
Map<String, DataModel.Flag> getCachedFlags(LDContext context);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.launchdarkly.sdk.android.subsystems;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.launchdarkly.logging.LDLogger;
import com.launchdarkly.sdk.LDContext;
Expand Down Expand Up @@ -31,6 +32,8 @@ public final class DataSourceBuildInputs {
private final SelectorSource selectorSource;
private final ScheduledExecutorService sharedExecutor;
private final File cacheDir;
@Nullable
private final CachedFlagStore cachedFlagStore;
private final LDLogger baseLogger;

/**
Expand All @@ -44,6 +47,8 @@ public final class DataSourceBuildInputs {
* @param sharedExecutor shared executor for scheduling tasks; owned and shut down by
* the calling data source, so components must not shut it down
* @param cacheDir the platform's cache directory for HTTP-level caching
* @param cachedFlagStore read access to cached flag data, or null if no persistent
* store is configured
* @param baseLogger the base logger instance
*/
public DataSourceBuildInputs(
Expand All @@ -54,6 +59,7 @@ public DataSourceBuildInputs(
SelectorSource selectorSource,
ScheduledExecutorService sharedExecutor,
@NonNull File cacheDir,
@Nullable CachedFlagStore cachedFlagStore,
LDLogger baseLogger
) {
this.evaluationContext = evaluationContext;
Expand All @@ -63,6 +69,7 @@ public DataSourceBuildInputs(
this.selectorSource = selectorSource;
this.sharedExecutor = sharedExecutor;
this.cacheDir = cacheDir;
this.cachedFlagStore = cachedFlagStore;
this.baseLogger = baseLogger;
}

Expand Down Expand Up @@ -133,6 +140,17 @@ public File getCacheDir() {
return cacheDir;
}

/**
* Returns read access to cached flag data, or null if no persistent store
* is configured. Used by the cache initializer to load stored flags.
*
* @return the cached flag store, or null
*/
@Nullable
public CachedFlagStore getCachedFlagStore() {
return cachedFlagStore;
}

/**
* Returns the base logger instance.
*
Expand Down