Skip to content

Commit 32922df

Browse files
authored
Store and update config metadata entries by namespace (#7373)
* Insert and load config metadata by namespace * Deprecate existing metadata table name * Update tests * Fix delete method and update naming * Add test for writing metadate for multiple namespaces
1 parent 05d9a01 commit 32922df

File tree

6 files changed

+187
-40
lines changed

6 files changed

+187
-40
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ FirebaseAuth/Tests/Sample/SwiftApiTests/Credentials.swift
99
FirebaseDatabase/Tests/Resources/GoogleService-Info.plist
1010

1111
FirebaseRemoteConfig/Tests/SwiftAPI/Resources/GoogleService-Info.plist
12+
FirebaseRemoteConfig/Tests/Sample/RemoteConfigSampleApp/GoogleService-Info.plist
13+
FirebaseRemoteConfig/Tests/Sample/RemoteConfigSampleApp/SecondApp-GoogleService-Info.plist
1214

1315
# FirebaseStorage integration tests GoogleService-Info.plist
1416
FirebaseStorage/Tests/Integration/Resources/GoogleService-Info.plist

FirebaseRemoteConfig/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Unreleased
2+
- [fixed] Store fetch metadata per namespace to address activation issues. (#7179)
3+
14
# v7.7.0
25
- [added] Added community support for watchOS. (#7481)
36

FirebaseRemoteConfig/Sources/RCNConfigDBManager.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ typedef NS_ENUM(NSInteger, RCNUpdateOption) {
2626

2727
/// Column names in metadata table
2828
static NSString *const RCNKeyBundleIdentifier = @"bundle_identifier";
29+
static NSString *const RCNKeyNamespace = @"namespace";
2930
static NSString *const RCNKeyFetchTime = @"fetch_time";
3031
static NSString *const RCNKeyDigestPerNamespace = @"digest_per_ns";
3132
static NSString *const RCNKeyDeviceContext = @"device_context";
@@ -63,9 +64,10 @@ typedef void (^RCNDBLoadCompletion)(BOOL success,
6364
/// Load config content from main table to cached memory during app start.
6465
- (void)loadMainWithBundleIdentifier:(NSString *)bundleIdentifier
6566
completionHandler:(RCNDBLoadCompletion)handler;
66-
/// Load config settings from metadata table to cached memory during app start. Config settings
67-
/// include success/failure fetch times, device contenxt, app context, etc.
68-
- (NSDictionary *)loadMetadataWithBundleIdentifier:(NSString *)bundleIdentifier;
67+
/// Load config settings for a given namespace from metadata table to cached memory during app
68+
/// start. Config settings include success/failure fetch times, device contenxt, app context, etc.
69+
- (NSDictionary *)loadMetadataWithBundleIdentifier:(NSString *)bundleIdentifier
70+
namespace:(NSString *)namespace;
6971
/// Load internal metadata from internal metadata table, such as customized HTTP connection/read
7072
/// timeout, throttling time interval and number limit of throttling, etc.
7173
/// This call needs to be blocking to ensure throttling works during apps starts.
@@ -101,6 +103,7 @@ typedef void (^RCNDBLoadCompletion)(BOOL success,
101103
completionHandler:(RCNDBCompletion)handler;
102104

103105
- (void)updateMetadataWithOption:(RCNUpdateOption)option
106+
namespace:(NSString *)namespace
104107
values:(NSArray *)values
105108
completionHandler:(RCNDBCompletion)handler;
106109

@@ -112,9 +115,10 @@ typedef void (^RCNDBLoadCompletion)(BOOL success,
112115
- (void)deleteRecordFromMainTableWithNamespace:(NSString *)namespace_p
113116
bundleIdentifier:(NSString *)bundleIdentifier
114117
fromSource:(RCNDBSource)source;
115-
/// Remove all the records of given package name from metadata/internal metadata DB before updating
116-
/// new values from response.
118+
/// Remove all the records of given package name and namespace from metadata/internal metadata DB
119+
/// before updating new values from response.
117120
- (void)deleteRecordWithBundleIdentifier:(NSString *)bundlerIdentifier
121+
namespace:(NSString *)namespace
118122
isInternalDB:(BOOL)isInternalDB;
119123
/// Remove all the records from a config content table.
120124
- (void)deleteAllRecordsFromTableWithSource:(RCNDBSource)source;

FirebaseRemoteConfig/Sources/RCNConfigDBManager.m

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
#define RCNTableNameMain "main"
2727
#define RCNTableNameMainActive "main_active"
2828
#define RCNTableNameMainDefault "main_default"
29-
#define RCNTableNameMetadata "fetch_metadata"
29+
#define RCNTableNameMetadataDeprecated "fetch_metadata"
30+
#define RCNTableNameMetadata "fetch_metadata_v2"
3031
#define RCNTableNameInternalMetadata "internal_metadata"
3132
#define RCNTableNameExperiment "experiment"
3233
#define RCNTableNamePersonalization "personalization"
@@ -98,9 +99,9 @@ static BOOL RemoteConfigCreateFilePathIfNotExist(NSString *filePath) {
9899

99100
static NSArray *RemoteConfigMetadataTableColumnsInOrder() {
100101
return @[
101-
RCNKeyBundleIdentifier, RCNKeyFetchTime, RCNKeyDigestPerNamespace, RCNKeyDeviceContext,
102-
RCNKeyAppContext, RCNKeySuccessFetchTime, RCNKeyFailureFetchTime, RCNKeyLastFetchStatus,
103-
RCNKeyLastFetchError, RCNKeyLastApplyTime, RCNKeyLastSetDefaultsTime
102+
RCNKeyBundleIdentifier, RCNKeyNamespace, RCNKeyFetchTime, RCNKeyDigestPerNamespace,
103+
RCNKeyDeviceContext, RCNKeyAppContext, RCNKeySuccessFetchTime, RCNKeyFailureFetchTime,
104+
RCNKeyLastFetchStatus, RCNKeyLastFetchError, RCNKeyLastApplyTime, RCNKeyLastSetDefaultsTime
104105
];
105106
}
106107

@@ -267,8 +268,8 @@ - (BOOL)createTableSchema {
267268

268269
static const char *createTableMetadata =
269270
"create TABLE IF NOT EXISTS " RCNTableNameMetadata
270-
" (_id INTEGER PRIMARY KEY, bundle_identifier"
271-
" TEXT, fetch_time INTEGER, digest_per_ns BLOB, device_context BLOB, app_context BLOB, "
271+
" (_id INTEGER PRIMARY KEY, bundle_identifier TEXT, namespace TEXT,"
272+
" fetch_time INTEGER, digest_per_ns BLOB, device_context BLOB, app_context BLOB, "
272273
"success_fetch_time BLOB, failure_fetch_time BLOB, last_fetch_status INTEGER, "
273274
"last_fetch_error INTEGER, last_apply_time INTEGER, last_set_defaults_time INTEGER)";
274275

@@ -354,9 +355,9 @@ - (BOOL)insertMetadataTableWithValues:(NSDictionary *)columnNameToValue {
354355
RCN_MUST_NOT_BE_MAIN_THREAD();
355356
static const char *SQL =
356357
"INSERT INTO " RCNTableNameMetadata
357-
" (bundle_identifier, fetch_time, digest_per_ns, device_context, "
358+
" (bundle_identifier, namespace, fetch_time, digest_per_ns, device_context, "
358359
"app_context, success_fetch_time, failure_fetch_time, last_fetch_status, "
359-
"last_fetch_error, last_apply_time, last_set_defaults_time) values (?, ?, ?, ?, ?, "
360+
"last_fetch_error, last_apply_time, last_set_defaults_time) values (?, ?, ?, ?, ?, ?, "
360361
"?, ?, ?, ?, ?, ?)";
361362

362363
sqlite3_stmt *statement = [self prepareSQL:SQL];
@@ -368,7 +369,8 @@ - (BOOL)insertMetadataTableWithValues:(NSDictionary *)columnNameToValue {
368369
NSArray *columns = RemoteConfigMetadataTableColumnsInOrder();
369370
int index = 0;
370371
for (NSString *columnName in columns) {
371-
if ([columnName isEqualToString:RCNKeyBundleIdentifier]) {
372+
if ([columnName isEqualToString:RCNKeyBundleIdentifier] ||
373+
[columnName isEqualToString:RCNKeyNamespace]) {
372374
NSString *value = columnNameToValue[columnName];
373375
if (![self bindStringToStatement:statement index:++index string:value]) {
374376
return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
@@ -618,10 +620,11 @@ - (BOOL)insertOrUpdatePersonalizationConfig:(NSDictionary *)dataValue
618620
#pragma mark - update
619621

620622
- (void)updateMetadataWithOption:(RCNUpdateOption)option
623+
namespace:(NSString *)namespace
621624
values:(NSArray *)values
622625
completionHandler:(RCNDBCompletion)handler {
623626
dispatch_async(_databaseOperationQueue, ^{
624-
BOOL success = [self updateMetadataTableWithOption:option andValues:values];
627+
BOOL success = [self updateMetadataTableWithOption:option namespace:namespace andValues:values];
625628
if (handler) {
626629
dispatch_async(dispatch_get_main_queue(), ^{
627630
handler(success, nil);
@@ -630,17 +633,20 @@ - (void)updateMetadataWithOption:(RCNUpdateOption)option
630633
});
631634
}
632635

633-
- (BOOL)updateMetadataTableWithOption:(RCNUpdateOption)option andValues:(NSArray *)values {
636+
- (BOOL)updateMetadataTableWithOption:(RCNUpdateOption)option
637+
namespace:(NSString *)namespace
638+
andValues:(NSArray *)values {
634639
RCN_MUST_NOT_BE_MAIN_THREAD();
635640
static const char *SQL =
636641
"UPDATE " RCNTableNameMetadata " (last_fetch_status, last_fetch_error, last_apply_time, "
637-
"last_set_defaults_time) values (?, ?, ?, ?)";
642+
"last_set_defaults_time) values (?, ?, ?, ?) WHERE namespace = ?";
638643
if (option == RCNUpdateOptionFetchStatus) {
639-
SQL = "UPDATE " RCNTableNameMetadata " SET last_fetch_status = ?, last_fetch_error = ?";
644+
SQL = "UPDATE " RCNTableNameMetadata
645+
" SET last_fetch_status = ?, last_fetch_error = ? WHERE namespace = ?";
640646
} else if (option == RCNUpdateOptionApplyTime) {
641-
SQL = "UPDATE " RCNTableNameMetadata " SET last_apply_time = ?";
647+
SQL = "UPDATE " RCNTableNameMetadata " SET last_apply_time = ? WHERE namespace = ?";
642648
} else if (option == RCNUpdateOptionDefaultTime) {
643-
SQL = "UPDATE " RCNTableNameMetadata " SET last_set_defaults_time = ?";
649+
SQL = "UPDATE " RCNTableNameMetadata " SET last_set_defaults_time = ? WHERE namespace = ?";
644650
} else {
645651
return NO;
646652
}
@@ -666,6 +672,12 @@ - (BOOL)updateMetadataTableWithOption:(RCNUpdateOption)option andValues:(NSArray
666672
return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
667673
}
668674
}
675+
// bind namespace to query
676+
if (sqlite3_bind_text(statement, ++index, [namespace UTF8String], -1, SQLITE_TRANSIENT) !=
677+
SQLITE_OK) {
678+
return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
679+
}
680+
669681
if (sqlite3_step(statement) != SQLITE_DONE) {
670682
return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO];
671683
}
@@ -674,31 +686,34 @@ - (BOOL)updateMetadataTableWithOption:(RCNUpdateOption)option andValues:(NSArray
674686
}
675687
#pragma mark - read from DB
676688

677-
- (NSDictionary *)loadMetadataWithBundleIdentifier:(NSString *)bundleIdentifier {
689+
- (NSDictionary *)loadMetadataWithBundleIdentifier:(NSString *)bundleIdentifier
690+
namespace:(NSString *)namespace {
678691
__block NSDictionary *metadataTableResult;
679692
__weak RCNConfigDBManager *weakSelf = self;
680693
dispatch_sync(_databaseOperationQueue, ^{
681-
metadataTableResult = [weakSelf loadMetadataTableWithBundleIdentifier:bundleIdentifier];
694+
metadataTableResult = [weakSelf loadMetadataTableWithBundleIdentifier:bundleIdentifier
695+
namespace:namespace];
682696
});
683697
if (metadataTableResult) {
684698
return metadataTableResult;
685699
}
686700
return [[NSDictionary alloc] init];
687701
}
688702

689-
- (NSMutableDictionary *)loadMetadataTableWithBundleIdentifier:(NSString *)bundleIdentifier {
703+
- (NSMutableDictionary *)loadMetadataTableWithBundleIdentifier:(NSString *)bundleIdentifier
704+
namespace:(NSString *)namespace {
690705
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
691706
const char *SQL =
692707
"SELECT bundle_identifier, fetch_time, digest_per_ns, device_context, app_context, "
693708
"success_fetch_time, failure_fetch_time , last_fetch_status, "
694709
"last_fetch_error, last_apply_time, last_set_defaults_time FROM " RCNTableNameMetadata
695-
" WHERE bundle_identifier = ?";
710+
" WHERE bundle_identifier = ? and namespace = ?";
696711
sqlite3_stmt *statement = [self prepareSQL:SQL];
697712
if (!statement) {
698713
return nil;
699714
}
700715

701-
NSArray *params = @[ bundleIdentifier ];
716+
NSArray *params = @[ bundleIdentifier, namespace ];
702717
[self bindStringsToStatement:statement stringArray:params];
703718

704719
while (sqlite3_step(statement) == SQLITE_ROW) {
@@ -1043,6 +1058,7 @@ - (void)deleteRecordFromMainTableWithNamespace:(NSString *)namespace_p
10431058
}
10441059

10451060
- (void)deleteRecordWithBundleIdentifier:(NSString *)bundleIdentifier
1061+
namespace:(NSString *)namespace
10461062
isInternalDB:(BOOL)isInternalDB {
10471063
__weak RCNConfigDBManager *weakSelf = self;
10481064
dispatch_async(_databaseOperationQueue, ^{
@@ -1051,10 +1067,11 @@ - (void)deleteRecordWithBundleIdentifier:(NSString *)bundleIdentifier
10511067
return;
10521068
}
10531069
const char *SQL = "DELETE FROM " RCNTableNameInternalMetadata " WHERE key LIKE ?";
1070+
NSArray *params = @[ bundleIdentifier ];
10541071
if (!isInternalDB) {
1055-
SQL = "DELETE FROM " RCNTableNameMetadata " WHERE bundle_identifier = ?";
1072+
SQL = "DELETE FROM " RCNTableNameMetadata " WHERE bundle_identifier = ? and namespace = ?";
1073+
params = @[ bundleIdentifier, namespace ];
10561074
}
1057-
NSArray *params = @[ bundleIdentifier ];
10581075
[strongSelf executeQuery:SQL withParams:params];
10591076
});
10601077
}

FirebaseRemoteConfig/Sources/RCNConfigSettings.m

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ - (void)updateLastFetchTimeInterval:(NSTimeInterval)lastFetchTimeInterval {
142142

143143
#pragma mark - load from DB
144144
- (NSDictionary *)loadConfigFromMetadataTable {
145-
NSDictionary *metadata = [[_DBManager loadMetadataWithBundleIdentifier:_bundleIdentifier] copy];
145+
NSDictionary *metadata = [[_DBManager loadMetadataWithBundleIdentifier:_bundleIdentifier
146+
namespace:_FIRNamespace] copy];
146147
if (metadata) {
147148
// TODO: Remove (all metadata in general) once ready to
148149
// migrate to user defaults completely.
@@ -180,7 +181,9 @@ - (NSDictionary *)loadConfigFromMetadataTable {
180181
// Update internal metadata content to cache and DB.
181182
- (void)updateInternalContentWithResponse:(NSDictionary *)response {
182183
// Remove all the keys with current pakcage name.
183-
[_DBManager deleteRecordWithBundleIdentifier:_bundleIdentifier isInternalDB:YES];
184+
[_DBManager deleteRecordWithBundleIdentifier:_bundleIdentifier
185+
namespace:_FIRNamespace
186+
isInternalDB:YES];
184187

185188
for (NSString *key in _internalMetadata.allKeys) {
186189
if ([key hasPrefix:_bundleIdentifier]) {
@@ -258,7 +261,9 @@ - (void)updateFetchTimeWithSuccessFetch:(BOOL)isSuccessfulFetch {
258261
}
259262

260263
- (void)updateMetadataTable {
261-
[_DBManager deleteRecordWithBundleIdentifier:_bundleIdentifier isInternalDB:NO];
264+
[_DBManager deleteRecordWithBundleIdentifier:_bundleIdentifier
265+
namespace:_FIRNamespace
266+
isInternalDB:NO];
262267
NSError *error;
263268
// Objects to be serialized cannot be invalid.
264269
if (!_bundleIdentifier) {
@@ -309,6 +314,7 @@ - (void)updateMetadataTable {
309314

310315
NSDictionary *columnNameToValue = @{
311316
RCNKeyBundleIdentifier : _bundleIdentifier,
317+
RCNKeyNamespace : _FIRNamespace,
312318
RCNKeyFetchTime : @(self.lastFetchTimeInterval),
313319
RCNKeyDigestPerNamespace : serializedDigestPerNamespace,
314320
RCNKeyDeviceContext : serializedDeviceContext,
@@ -379,6 +385,7 @@ - (void)setLastFetchError:(FIRRemoteConfigError)lastFetchError {
379385
if (_lastFetchError != lastFetchError) {
380386
_lastFetchError = lastFetchError;
381387
[_DBManager updateMetadataWithOption:RCNUpdateOptionFetchStatus
388+
namespace:_FIRNamespace
382389
values:@[ @(_lastFetchStatus), @(_lastFetchError) ]
383390
completionHandler:nil];
384391
}
@@ -428,13 +435,15 @@ - (void)setFetchTimeout:(NSTimeInterval)fetchTimeout {
428435
- (void)setLastApplyTimeInterval:(NSTimeInterval)lastApplyTimestamp {
429436
_lastApplyTimeInterval = lastApplyTimestamp;
430437
[_DBManager updateMetadataWithOption:RCNUpdateOptionApplyTime
438+
namespace:_FIRNamespace
431439
values:@[ @(lastApplyTimestamp) ]
432440
completionHandler:nil];
433441
}
434442

435443
- (void)setLastSetDefaultsTimeInterval:(NSTimeInterval)lastSetDefaultsTimestamp {
436444
_lastSetDefaultsTimeInterval = lastSetDefaultsTimestamp;
437445
[_DBManager updateMetadataWithOption:RCNUpdateOptionDefaultTime
446+
namespace:_FIRNamespace
438447
values:@[ @(lastSetDefaultsTimestamp) ]
439448
completionHandler:nil];
440449
}

0 commit comments

Comments
 (0)