Skip to content

Commit

Permalink
Feature flags performance improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert committed Dec 13, 2024
1 parent 615a965 commit 55498e8
Show file tree
Hide file tree
Showing 23 changed files with 748 additions and 276 deletions.
98 changes: 75 additions & 23 deletions Bugsnag.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions Bugsnag/BugsnagInternals.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#import "BugsnagHandledState.h"
#import "BugsnagNotifier.h"

@interface BSGFeatureFlagStore : NSObject <NSCopying>
@interface BSGMemoryFeatureFlagStore : NSObject <NSCopying>
@end

NS_ASSUME_NONNULL_BEGIN
Expand Down Expand Up @@ -79,7 +79,7 @@ typedef void (^ BSGClientObserver)(BSGClientObserverEvent event, _Nullable id va

@property (retain, nonatomic) BugsnagConfiguration *configuration;

@property (readonly, nonatomic) BSGFeatureFlagStore *featureFlagStore;
@property (readonly, nonatomic) BSGMemoryFeatureFlagStore *featureFlagStore;

@property (strong, nonatomic) BugsnagMetadata *metadata;

Expand Down Expand Up @@ -161,7 +161,7 @@ typedef void (^ BSGClientObserver)(BSGClientObserverEvent event, _Nullable id va

- (NSDictionary *)toJsonWithRedactedKeys:(nullable NSSet *)redactedKeys;

@property (readwrite, strong, nonnull, nonatomic) BSGFeatureFlagStore *featureFlagStore;
@property (readwrite, strong, nonnull, nonatomic) BSGMemoryFeatureFlagStore *featureFlagStore;

@end

Expand Down
3 changes: 3 additions & 0 deletions Bugsnag/Client/BugsnagClient+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
@class BugsnagNotifier;
@class BugsnagSessionTracker;
@class BugsnagSystemState;
@class BSGPersistentFeatureFlagStore;

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -67,6 +68,8 @@ BSG_OBJC_DIRECT_MEMBERS
/// }
@property (strong, nonatomic) BugsnagMetadata *state;

@property (strong, nonatomic) BSGPersistentFeatureFlagStore *featureFlags;

@property (strong, nonatomic) NSMutableArray *stateEventBlocks;

@property (strong, nonatomic) BugsnagSystemState *systemState;
Expand Down
21 changes: 12 additions & 9 deletions Bugsnag/Client/BugsnagClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
#import "BugsnagUser+Private.h"
#import "BSGPersistentDeviceID.h"
#import "BugsnagCocoaPerformanceFromBugsnagCocoa.h"
#import "BSGPersistentFeatureFlagStore.h"

static struct {
// Contains the user-specified metadata, including the user tab from config.
Expand Down Expand Up @@ -141,6 +142,7 @@ static void BSSerializeDataCrashHandler(const BSG_KSCrashReportWriter *writer, b
writer->addIntegerElement(writer, "thermalState", bsg_runContext->thermalState);

BugsnagBreadcrumbsWriteCrashReport(writer, requiresAsyncSafety);
BugsnagFeatureFlagsWriteCrashReport(writer, requiresAsyncSafety);

// Create a file to indicate that the crash has been handled by
// the library. This exists in case the subsequent `onCrash` handler
Expand Down Expand Up @@ -213,11 +215,11 @@ - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration {
}

_featureFlagStore = [configuration.featureFlagStore copy];
_featureFlagStore.isMainStore = YES;

_state = [[BugsnagMetadata alloc] initWithDictionary:@{
BSGKeyClient: @{
BSGKeyContext: _configuration.context ?: [NSNull null],
BSGKeyFeatureFlags: BSGFeatureFlagStoreToJSON(_featureFlagStore),
},
BSGKeyUser: [_configuration.user toJson] ?: @{}
}];
Expand All @@ -236,6 +238,8 @@ - (instancetype)initWithConfiguration:(BugsnagConfiguration *)configuration {
bsg_g_bugsnag_data.onCrash = (void (*)(const BSG_KSCrashReportWriter *))self.configuration.onCrashHandler;

_breadcrumbStore = [[BugsnagBreadcrumbs alloc] initWithConfiguration:self.configuration];

_featureFlags = [[BSGPersistentFeatureFlagStore alloc] initWithStorageDirectory:fileLocations.featureFlags];

// Start with a copy of the configuration metadata
self.metadata = [[_configuration metadata] copy];
Expand Down Expand Up @@ -285,6 +289,7 @@ - (void)start {
[self.metadata setStorageBuffer:&bsg_g_bugsnag_data.metadataJSON file:BSGFileLocations.current.metadata];
[self.state setStorageBuffer:&bsg_g_bugsnag_data.stateJSON file:BSGFileLocations.current.state];
[self.breadcrumbStore removeAllBreadcrumbs];
[self.featureFlags clear];

#if BSG_HAVE_REACHABILITY
[self setupConnectivityListener];
Expand Down Expand Up @@ -883,7 +888,7 @@ - (void)dealloc {
- (void)addFeatureFlagWithName:(NSString *)name variant:(nullable NSString *)variant {
@synchronized (self.featureFlagStore) {
BSGFeatureFlagStoreAddFeatureFlag(self.featureFlagStore, name, variant);
[self.state addMetadata:BSGFeatureFlagStoreToJSON(self.featureFlagStore) withKey:BSGKeyFeatureFlags toSection:BSGKeyClient];
[self.featureFlags addFeatureFlag:name withVariant:variant];
}
if (self.observer) {
self.observer(BSGClientObserverAddFeatureFlag, [BugsnagFeatureFlag flagWithName:name variant:variant]);
Expand All @@ -893,7 +898,7 @@ - (void)addFeatureFlagWithName:(NSString *)name variant:(nullable NSString *)var
- (void)addFeatureFlagWithName:(NSString *)name {
@synchronized (self.featureFlagStore) {
BSGFeatureFlagStoreAddFeatureFlag(self.featureFlagStore, name, nil);
[self.state addMetadata:BSGFeatureFlagStoreToJSON(self.featureFlagStore) withKey:BSGKeyFeatureFlags toSection:BSGKeyClient];
[self.featureFlags addFeatureFlag:name withVariant:nil];
}
if (self.observer) {
self.observer(BSGClientObserverAddFeatureFlag, [BugsnagFeatureFlag flagWithName:name]);
Expand All @@ -903,7 +908,7 @@ - (void)addFeatureFlagWithName:(NSString *)name {
- (void)addFeatureFlags:(NSArray<BugsnagFeatureFlag *> *)featureFlags {
@synchronized (self.featureFlagStore) {
BSGFeatureFlagStoreAddFeatureFlags(self.featureFlagStore, featureFlags);
[self.state addMetadata:BSGFeatureFlagStoreToJSON(self.featureFlagStore) withKey:BSGKeyFeatureFlags toSection:BSGKeyClient];
[self.featureFlags addFeatureFlags:featureFlags];
}
if (self.observer) {
for (BugsnagFeatureFlag *featureFlag in featureFlags) {
Expand All @@ -915,7 +920,7 @@ - (void)addFeatureFlags:(NSArray<BugsnagFeatureFlag *> *)featureFlags {
- (void)clearFeatureFlagWithName:(NSString *)name {
@synchronized (self.featureFlagStore) {
BSGFeatureFlagStoreClear(self.featureFlagStore, name);
[self.state addMetadata:BSGFeatureFlagStoreToJSON(self.featureFlagStore) withKey:BSGKeyFeatureFlags toSection:BSGKeyClient];
[self.featureFlags clear:name];
}
if (self.observer) {
self.observer(BSGClientObserverClearFeatureFlag, name);
Expand All @@ -925,7 +930,7 @@ - (void)clearFeatureFlagWithName:(NSString *)name {
- (void)clearFeatureFlags {
@synchronized (self.featureFlagStore) {
BSGFeatureFlagStoreClear(self.featureFlagStore, nil);
[self.state addMetadata:BSGFeatureFlagStoreToJSON(self.featureFlagStore) withKey:BSGKeyFeatureFlags toSection:BSGKeyClient];
[self.featureFlags clear];
}
if (self.observer) {
self.observer(BSGClientObserverClearFeatureFlag, nil);
Expand Down Expand Up @@ -1225,9 +1230,7 @@ - (nullable BugsnagEvent *)generateEventForLastLaunchWithError:(BugsnagError *)e
session:session];

event.context = stateDict[BSGKeyClient][BSGKeyContext];

id featureFlags = stateDict[BSGKeyClient][BSGKeyFeatureFlags];
event.featureFlagStore = BSGFeatureFlagStoreFromJSON(featureFlags);
event.featureFlagStore = BSGFeatureFlagStoreWithFlags([self.featureFlags allFlags]);

return event;
}
Expand Down
2 changes: 1 addition & 1 deletion Bugsnag/Configuration/BugsnagConfiguration+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ BSG_OBJC_DIRECT_MEMBERS

@property (readonly, nonatomic) NSDictionary<NSString *, id> *dictionaryRepresentation;

@property (nonatomic) BSGFeatureFlagStore *featureFlagStore;
@property (nonatomic) BSGMemoryFeatureFlagStore *featureFlagStore;

@property (copy, nonatomic) BugsnagMetadata *metadata;

Expand Down
6 changes: 3 additions & 3 deletions Bugsnag/Configuration/BugsnagConfiguration.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

#import "BSGConfigurationBuilder.h"
#import "BSGDefines.h"
#import "BSGFeatureFlagStore.h"
#import "BSGMemoryFeatureFlagStore.h"
#import "BSGKeys.h"
#import "BugsnagApiClient.h"
#import "BugsnagEndpointConfiguration.h"
Expand Down Expand Up @@ -166,7 +166,7 @@ - (instancetype)initWithApiKey:(NSString *)apiKey {
if (apiKey) {
[self setApiKey:apiKey];
}
_featureFlagStore = [[BSGFeatureFlagStore alloc] init];
_featureFlagStore = [[BSGMemoryFeatureFlagStore alloc] init];
_metadata = [[BugsnagMetadata alloc] init];
_endpoints = [BugsnagEndpointConfiguration new];
_autoDetectErrors = YES;
Expand Down Expand Up @@ -241,7 +241,7 @@ - (instancetype)initWithDictionaryRepresentation:(NSDictionary<NSString *, id> *
_bundleVersion = dictionaryRepresentation[BSGKeyBundleVersion];
_context = dictionaryRepresentation[BSGKeyContext];
_enabledReleaseStages = dictionaryRepresentation[BSGKeyEnabledReleaseStages];
_featureFlagStore = [[BSGFeatureFlagStore alloc] init];
_featureFlagStore = [[BSGMemoryFeatureFlagStore alloc] init];
_releaseStage = dictionaryRepresentation[BSGKeyReleaseStage];
return self;
}
Expand Down
2 changes: 1 addition & 1 deletion Bugsnag/Delivery/BSGEventUploadKSCrashReportOperation.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
return nil;
}
NSMutableArray *keys = [NSMutableArray array];
NSString *pattern = @"\"(report|process|system|system_atcrash|binary_images|crash|threads|error|user_atcrash|config|metaData|state|breadcrumbs)\":";
NSString *pattern = @"\"(report|process|system|system_atcrash|binary_images|crash|threads|error|user_atcrash|config|metaData|state|breadcrumbs|featureFlags)\":";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:nil];
for (NSTextCheckingResult *result in [regex matchesInString:string options:0 range:NSMakeRange(0, string.length)]) {
if ([result numberOfRanges] == 2) {
Expand Down
56 changes: 56 additions & 0 deletions Bugsnag/FeatureFlags/BSGMemoryFeatureFlagStore.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// BSGMemoryFeatureFlagStore.h
// Bugsnag
//
// Created by Nick Dowell on 11/11/2021.
// Copyright © 2021 Bugsnag Inc. All rights reserved.
//

#import "BugsnagInternals.h"
#import "BSGDefines.h"

NS_ASSUME_NONNULL_BEGIN

void BSGFeatureFlagStoreAddFeatureFlag(BSGMemoryFeatureFlagStore *store, NSString *name, NSString *_Nullable variant);

void BSGFeatureFlagStoreAddFeatureFlags(BSGMemoryFeatureFlagStore *store, NSArray<BugsnagFeatureFlag *> *featureFlags);

void BSGFeatureFlagStoreClear(BSGMemoryFeatureFlagStore *store, NSString *_Nullable name);

NSArray<NSDictionary *> * BSGFeatureFlagStoreToJSON(BSGMemoryFeatureFlagStore *store);

BSGMemoryFeatureFlagStore * BSGFeatureFlagStoreFromJSON(id _Nullable json);
BSGMemoryFeatureFlagStore * BSGFeatureFlagStoreWithFlags(NSArray<BugsnagFeatureFlag *> *);


BSG_OBJC_DIRECT_MEMBERS
@interface BSGMemoryFeatureFlagStore ()

@property(nonatomic,nonnull,readonly) NSArray<BugsnagFeatureFlag *> * allFlags;
@property(nonatomic) BOOL isMainStore;

+ (nonnull BSGMemoryFeatureFlagStore *) fromJSON:(nonnull id)json;
+ (nonnull BSGMemoryFeatureFlagStore *)withFlags:(NSArray<BugsnagFeatureFlag *> *)flags;

- (NSUInteger) count;

- (void) addFeatureFlag:(nonnull NSString *)name withVariant:(nullable NSString *)variant;

- (void) addFeatureFlags:(nonnull NSArray<BugsnagFeatureFlag *> *)featureFlags;

- (void) clear:(nullable NSString *)name;

- (nonnull NSArray<NSDictionary *> *) toJSON;

@end

#pragma mark -

/**
* Inserts the current feature flags into a crash report.
*
*/
void BugsnagFeatureFlagsWriteCrashReport(const BSG_KSCrashReportWriter * _Nonnull writer,
bool requiresAsyncSafety);

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 55498e8

Please sign in to comment.