Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rc-swift] ConfigDBManager.swift #14126

Merged
merged 11 commits into from
Nov 22, 2024
Merged

[rc-swift] ConfigDBManager.swift #14126

merged 11 commits into from
Nov 22, 2024

Conversation

paulb777
Copy link
Member

@paulb777 paulb777 commented Nov 14, 2024

  • Implements RC's underlying ConfigDBManager in Swift
  • Migrates database queue to an actor
  • Refactors some of the mocks out of the the unit tests
  • Pod testing works on Xcode 16. Other CI failures look to be transition-related

@google-oss-bot
Copy link

1 Warning
⚠️ Did you forget to add a changelog entry? (Add #no-changelog to the PR description to silence this warning.)

Generated by 🚫 Danger

Copy link
Contributor

github-actions bot commented Nov 14, 2024

Apple API Diff Report

Commit: 0095daf
Last updated: Thu Nov 21 18:37 PST 2024
View workflow logs & download artifacts


FirebaseRemoteConfig

Classes

FIRRemoteConfigValue
[ADDED] -initWithData:source:
Swift:
+  init ( data : Data ?, source : RemoteConfigSource )
Objective-C:
+  - ( instancetype _Nonnull ) initWithData :( nullable NSData * ) data source :( FIRRemoteConfigSource ) source ;

@@ -84,83 +84,83 @@ jobs:
scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb ${{ matrix.podspec }} --platforms=${{ matrix.target }} \
${{ matrix.build-env.tests }}

spm-package-resolved:
Copy link
Member Author

Choose a reason for hiding this comment

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

No SPM while using ObjC unit tests in transition

@@ -26,7 +26,7 @@ @implementation FIRRemoteConfigValue {
}

/// Designated initializer
- (instancetype)initWithData:(NSData *)data source:(FIRRemoteConfigSource)source {
- (instancetype)initWithData:(nullable NSData *)data source:(FIRRemoteConfigSource)source {
Copy link
Member Author

Choose a reason for hiding this comment

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

fix for existing api usage

@@ -193,6 +194,21 @@ - (instancetype)initWithAppName:(NSString *)appName
return self;
}

- (instancetype)initWithAppName:(NSString *)appName
Copy link
Member Author

Choose a reason for hiding this comment

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

Inject userDefaults for testing. This will be a single init with an optional when it goes to Swift

@@ -21,7 +21,7 @@
@class RCNConfigDBManager;

/// This internal class contains a set of variables that are unique among all the config instances.
/// It also handles all metadata and internal metadata. This class is not thread safe and does not
Copy link
Member Author

Choose a reason for hiding this comment

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

Internal metadata handling was dead code. See #14153

@@ -66,8 +79,6 @@ @interface RCNConfigSettings () {
NSString *_googleAppID;
/// The user defaults manager scoped to this RC instance of FIRApp and namespace.
RCNUserDefaultsManager *_userDefaultsManager;
/// The timestamp of last eTag update.
NSTimeInterval _lastETagUpdateTime;
Copy link
Member Author

Choose a reason for hiding this comment

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

unused

}
return metadata;
- (void)loadConfigFromMetadataTable {
[_DBManager
Copy link
Member Author

Choose a reason for hiding this comment

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

Fixes synchronous db reads from ObjC

Copy link
Member

Choose a reason for hiding this comment

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

Do clients of this API need to change now that it's async?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes. That should be done in this PR

@@ -0,0 +1,376 @@
// Copyright 2024 Google LLC
Copy link
Member Author

Choose a reason for hiding this comment

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

This file is the internal API for the DB. The guts of the implementation is in DatabaseActor which is the code that was previously in a dedicated queue.

@paulb777 paulb777 marked this pull request as ready for review November 21, 2024 06:19
Copy link
Contributor

@andrewheard andrewheard left a comment

Choose a reason for hiding this comment

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

This looks reasonable to me. There are potentially some DB optimizations we could do (e.g., creating the prepared statements once and resetting them to bind new values and then finalizing them on deinit) but I think that's beyond the scope of this Swift re-write and would be better to leave it closer to the original implementation (especially since you weren't sure if we wanted to keep the sqlite implementation).

Comment on lines 335 to 336
NSLog(@"%f %f", strongSelf->_settings.lastETagUpdateTime,
strongSelf->_settings.lastApplyTimeInterval);
Copy link
Member

@ncooke3 ncooke3 Nov 21, 2024

Choose a reason for hiding this comment

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

Is checking this diff in intentional? Maybe should be deleted?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep - good catch - removing

}
return metadata;
- (void)loadConfigFromMetadataTable {
[_DBManager
Copy link
Member

Choose a reason for hiding this comment

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

Do clients of this API need to change now that it's async?

return internalMetadata
}

private func migrateV1Namespace(toV2Namespace: Void) {
Copy link
Member

Choose a reason for hiding this comment

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

I think the toV2Namespace is useless.

Suggested change
private func migrateV1Namespace(toV2Namespace: Void) {
private func migrateV1NamespaceToV2Namespace() {


func insertMetadataTable(withValues columnNameToValue: [String: Any]) -> Bool {
let sql = """
INSERT into fetch_metadata (\
Copy link
Member

Choose a reason for hiding this comment

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

I think this is inserting into the wrong table. It should be fetch_metadata_v2.

The objc impl:

#define RCNTableNameMetadata "fetch_metadata_v2"

/* snip */

  static const char *SQL =
      "INSERT INTO " RCNTableNameMetadata
      " (bundle_identifier, namespace, fetch_time, digest_per_ns, device_context, "
      "app_context, success_fetch_time, failure_fetch_time, last_fetch_status, "
      "last_fetch_error, last_apply_time, last_set_defaults_time) values (?, ?, ?, ?, ?, ?, "
      "?, ?, ?, ?, ?, ?)";
Suggested change
INSERT into fetch_metadata (\
INSERT into fetch_metadata_v2 (\

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes - good catch - It's sometimes surprising what the AI misses.

Comment on lines 336 to 341
sql = "UPDATE fetch_metadata SET last_apply_time = ? WHERE namespace = ?"
case .defaultTime:
sql = "UPDATE fetch_metadata SET last_set_defaults_time = ? WHERE namespace = ?"
case .fetchStatus:
sql =
"UPDATE fetch_metadata SET last_fetch_status = ?, last_fetch_error = ? WHERE namespace = ?"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
sql = "UPDATE fetch_metadata SET last_apply_time = ? WHERE namespace = ?"
case .defaultTime:
sql = "UPDATE fetch_metadata SET last_set_defaults_time = ? WHERE namespace = ?"
case .fetchStatus:
sql =
"UPDATE fetch_metadata SET last_fetch_status = ?, last_fetch_error = ? WHERE namespace = ?"
sql = "UPDATE fetch_metadata_v2 SET last_apply_time = ? WHERE namespace = ?"
case .defaultTime:
sql = "UPDATE fetch_metadata_v2 SET last_set_defaults_time = ? WHERE namespace = ?"
case .fetchStatus:
sql =
"UPDATE fetch_metadata_v2 SET last_fetch_status = ?, last_fetch_error = ? WHERE namespace = ?"

last_fetch_error, \
last_apply_time, \
last_set_defaults_time \
FROM fetch_metadata \
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
FROM fetch_metadata \
FROM fetch_metadata_v2 \

"""

let createMetadata = """
CREATE TABLE IF NOT EXISTS fetch_metadata (
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
CREATE TABLE IF NOT EXISTS fetch_metadata (
CREATE TABLE IF NOT EXISTS fetch_metadata_v2 (

@paulb777
Copy link
Member Author

I commented or resolved all comments except for most of the ones in DatabaseActor which I'll look at in a few hours

@paulb777
Copy link
Member Author

Going to merge it here. Thanks for the reviews @ncooke3 and @andrewheard.

One note is that callbacks from the Database APIs are not wrapped in main thread because they're already in a Task, can cause deadlocks and should be replaced by async APIs when the callers are in Swift.

@paulb777 paulb777 merged commit 06d4e4d into rc-swift Nov 22, 2024
32 of 38 checks passed
@paulb777 paulb777 deleted the pb-config-db-manager branch November 22, 2024 03:13
@paulb777
Copy link
Member Author

After merging, I rebased rc-swift to the latest main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants