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
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ plugins {
id 'jacoco-report-aggregation'
id "com.github.spotbugs" version libs.versions.spotbugs
id "org.owasp.dependencycheck" version libs.versions.depcheck
id 'me.champeau.jmh' version '0.6.8' // Added JMH plugin
}


Expand Down Expand Up @@ -55,6 +56,10 @@ dependencies {

compileOnly libs.lombok
annotationProcessor libs.lombok

// JMH dependencies
implementation 'org.openjdk.jmh:jmh-core:1.37'
annotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.37'
}

group = 'io.harness'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import java.util.concurrent.TimeUnit;

@Slf4j
public class EventExamplePoC {
public class EventExampleWithFeatureSnapshot {
private static final String SDK_KEY = "";
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

Expand Down
19 changes: 3 additions & 16 deletions src/main/java/io/harness/cf/client/api/InnerClient.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.harness.cf.client.api;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.harness.cf.client.common.SdkCodes;
import io.harness.cf.client.connector.*;
Expand All @@ -11,7 +10,6 @@
import io.harness.cf.model.Variation;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
Expand Down Expand Up @@ -319,7 +317,7 @@ public List<FeatureSnapshot> getFeatureSnapshots() {
}

public List<FeatureSnapshot> getFeatureSnapshots(String prefix) {
if (!options.isEnableFeatureSnapshot()){
if (!options.isEnableFeatureSnapshot()) {
log.debug("FeatureSnapshot disabled, snapshot will contain only current version.");
}
List<String> identifiers = repository.getAllFeatureIdentifiers(prefix);
Expand All @@ -334,21 +332,10 @@ public List<FeatureSnapshot> getFeatureSnapshots(String prefix) {
}

public FeatureSnapshot getFeatureSnapshot(@NonNull String identifier) {
if (!options.isEnableFeatureSnapshot()){
if (!options.isEnableFeatureSnapshot()) {
log.debug("FeatureSnapshot disabled, snapshot will contain only current version.");
}
Optional<FeatureConfig[]> ofc = repository.getCurrentAndPreviousFeatureConfig(identifier);
FeatureSnapshot result = new FeatureSnapshot();
if (ofc.isPresent()) {
FeatureConfig[] fc = ofc.get();
result.setPrevious(fc[0]);
result.setCurrent(fc[1]);
}
// this is here to create a deep copy of the object before its returned.
// this way we protect the cache.
Gson gson = new Gson();
FeatureSnapshot deepCopySnapshot = gson.fromJson(gson.toJson(result), FeatureSnapshot.class);
return deepCopySnapshot;
return repository.getFeatureSnapshot(identifier);
}

public void on(@NonNull final Event event, @NonNull final Consumer<String> consumer) {
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/io/harness/cf/client/api/Query.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.harness.cf.client.api;

import io.harness.cf.model.FeatureConfig;
import io.harness.cf.model.FeatureSnapshot;
import io.harness.cf.model.Segment;
import java.util.List;
import java.util.Optional;
Expand All @@ -14,7 +15,7 @@ public interface Query {

List<String> findFlagsBySegment(@NonNull String identifier);

Optional<FeatureConfig[]> getCurrentAndPreviousFeatureConfig(@NonNull String identifier);
FeatureSnapshot getFeatureSnapshot(@NonNull String identifier);

List<String> getAllFeatureIdentifiers(String prefix);
}
32 changes: 32 additions & 0 deletions src/main/java/io/harness/cf/client/api/StorageRepository.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.harness.cf.client.api;

import com.google.gson.Gson;
import io.harness.cf.client.common.Cache;
import io.harness.cf.client.common.Storage;
import io.harness.cf.client.common.Utils;
Expand Down Expand Up @@ -98,6 +99,37 @@ public Optional<FeatureConfig[]> getCurrentAndPreviousFeatureConfig(@NonNull Str
return Optional.empty();
}

public FeatureSnapshot getFeatureSnapshot(@NonNull String identifier) {
Gson gson = new Gson();
final String flagKey = formatFlagKey(identifier);
final String pFlagKey = formatPrevFlagKey(identifier);

FeatureConfig pFlag = (FeatureConfig) cache.get(pFlagKey);
FeatureConfig cFlag = (FeatureConfig) cache.get(flagKey);

if (cFlag != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should there be a null check for pFlag as well here? I'm assuming there is an assumption that if we dont have the current then we wont have the previous.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the previous flag does not exist we still want to package that to the snapshot even if its null.

FeatureSnapshot deepCopySnapshot =
gson.fromJson(gson.toJson(new FeatureSnapshot(cFlag, pFlag)), FeatureSnapshot.class);
return deepCopySnapshot;
}
// if we don't have it in cache we check the file
if (this.store != null) {
pFlag = (FeatureConfig) store.get(pFlagKey);
cFlag = (FeatureConfig) store.get(flagKey);
if (pFlag != null) {
cache.set(pFlagKey, pFlag);
}
if (cFlag != null) {
cache.set(flagKey, cFlag);
}

FeatureSnapshot deepCopySnapshot =
gson.fromJson(gson.toJson(new FeatureSnapshot(cFlag, pFlag)), FeatureSnapshot.class);
return deepCopySnapshot;
}
return null;
}

public Optional<Segment> getSegment(@NonNull String identifier, boolean cacheable) {
final String segmentKey = formatSegmentKey(identifier);
Segment segment = (Segment) cache.get(segmentKey);
Expand Down
63 changes: 31 additions & 32 deletions src/test/java/io/harness/cf/client/api/StorageRepositoryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import com.google.gson.Gson;
import io.harness.cf.model.FeatureConfig;
import io.harness.cf.model.FeatureSnapshot;
import java.awt.*;
import java.io.File;
import java.io.IOException;
Expand All @@ -12,17 +13,13 @@
import java.nio.file.Paths;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import lombok.NonNull;
import org.junit.jupiter.api.Test;

class StorageRepositoryTest {
private final Gson gson = new Gson();

// initialize the config and load the flags.
// load the test

@Test
void shouldInitialiseRepo() {
final Repository repository = new StorageRepository(new CaffeineCache(10000), null, false);
Expand All @@ -43,12 +40,10 @@ void shouldStoreCurrentConfig() throws Exception {
loadFlags(repository, makeFeatureList(featureConfig));
loadFlags(repository, makeFeatureList(featureConfigUpdated));

Optional<FeatureConfig[]> res =
repository.getCurrentAndPreviousFeatureConfig(featureConfigUpdated.getFeature());
FeatureConfig[] resFc = res.get();
FeatureSnapshot res = repository.getFeatureSnapshot(featureConfigUpdated.getFeature());

FeatureConfig previous = resFc[0];
FeatureConfig current = resFc[1];
FeatureConfig previous = res.getPrevious();
FeatureConfig current = res.getCurrent();

// check if previous version is null
assertNull(previous);
Expand Down Expand Up @@ -79,12 +74,10 @@ void shouldStoreCurrentConfigWithFileStore() throws Exception {
loadFlags(repository, makeFeatureList(featureConfig));
loadFlags(repository, makeFeatureList(featureConfigUpdated));

Optional<FeatureConfig[]> res =
repository.getCurrentAndPreviousFeatureConfig(featureConfigUpdated.getFeature());
FeatureConfig[] resFc = res.get();
FeatureSnapshot res = repository.getFeatureSnapshot(featureConfigUpdated.getFeature());

FeatureConfig previous = resFc[0];
FeatureConfig current = resFc[1];
FeatureConfig previous = res.getPrevious();
FeatureConfig current = res.getCurrent();

// check if previous version is null
assertNull(previous);
Expand Down Expand Up @@ -115,12 +108,10 @@ void shouldStorePreviousAndCurrentConfigWithFileStore() throws Exception {
loadFlags(repository, makeFeatureList(featureConfig));
loadFlags(repository, makeFeatureList(featureConfigUpdated));

Optional<FeatureConfig[]> res =
repository.getCurrentAndPreviousFeatureConfig(featureConfigUpdated.getFeature());
FeatureConfig[] resFc = res.get();
FeatureSnapshot res = repository.getFeatureSnapshot(featureConfigUpdated.getFeature());

FeatureConfig previous = resFc[0];
FeatureConfig current = resFc[1];
FeatureConfig previous = res.getPrevious();
FeatureConfig current = res.getCurrent();

// check if previous version is null
assertNotNull(previous);
Expand All @@ -145,12 +136,10 @@ void shouldStorePreviousAndCurrentConfig() throws Exception {
loadFlags(repository, makeFeatureList(featureConfig));
loadFlags(repository, makeFeatureList(featureConfigUpdated));

Optional<FeatureConfig[]> res =
repository.getCurrentAndPreviousFeatureConfig(featureConfigUpdated.getFeature());
FeatureConfig[] resFc = res.get();
FeatureSnapshot res = repository.getFeatureSnapshot(featureConfigUpdated.getFeature());

FeatureConfig previous = resFc[0];
FeatureConfig current = resFc[1];
FeatureConfig previous = res.getPrevious();
FeatureConfig current = res.getCurrent();

// check if previous version is null
assertNotNull(previous);
Expand All @@ -177,12 +166,10 @@ void shouldDeletePreviousAndCurrentConfig() throws Exception {

String featureIdentifier = featureConfig.getFeature();

Optional<FeatureConfig[]> res =
repository.getCurrentAndPreviousFeatureConfig(featureIdentifier);
FeatureConfig[] resFc = res.get();
FeatureSnapshot res = repository.getFeatureSnapshot(featureConfigUpdated.getFeature());

FeatureConfig previous = resFc[0];
FeatureConfig current = resFc[1];
FeatureConfig previous = res.getPrevious();
FeatureConfig current = res.getCurrent();

// check if previous version is null
assertNotNull(previous);
Expand All @@ -194,10 +181,9 @@ void shouldDeletePreviousAndCurrentConfig() throws Exception {

// delete config
repository.deleteFlag(featureIdentifier);
Optional<FeatureConfig[]> result =
repository.getCurrentAndPreviousFeatureConfig(featureIdentifier);
FeatureSnapshot result = repository.getFeatureSnapshot(featureConfigUpdated.getFeature());

assertFalse(result.isPresent(), "The Optional should be empty");
assertNull(result, "The Optional should be empty");
}

@Test
Expand Down Expand Up @@ -269,4 +255,17 @@ private FeatureConfig GetFeatureConfigFromFile() throws Exception {
}
return null;
}

private List<FeatureConfig> createBenchmarkData(int flagNumber, int version) throws Exception {
FeatureConfig fg = GetFeatureConfigFromFile();
List<FeatureConfig> list = new LinkedList<FeatureConfig>();
for (int i = 1; i <= flagNumber; i++) {
FeatureConfig f = fg;
f.setFeature("simpleBool" + i);
f.setVersion(new Long(version));
list.add(f);
}
// System.out.println(list);
return list;
}
}
Loading