-
Notifications
You must be signed in to change notification settings - Fork 2
[AIT-207] Partial object sync #117
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
Open
lawrence-forooghian
wants to merge
4
commits into
AIT-322-v6-ProtocolMessage
Choose a base branch
from
AIT-207-partial-object-sync
base: AIT-322-v6-ProtocolMessage
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+585
−86
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
9c20eb8
Add Equatable conformance to InboundObjectMessage
lawrence-forooghian 98178fc
Extract SyncObjectsPool struct
lawrence-forooghian 8631a18
Port OBJECT_SYNC sequence integration tests from ably-js
lawrence-forooghian 12faf8b
Implement partial object sync (RTO5f)
lawrence-forooghian File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| import Foundation | ||
|
|
||
| /// The RTO5f collection of objects gathered during an `OBJECT_SYNC` sequence, ready to be applied to the `ObjectsPool`. | ||
| /// | ||
| /// Every stored message is guaranteed to have a non-nil `.object` with either `.map` or `.counter` populated. | ||
| internal struct SyncObjectsPool: Collection { | ||
| /// Keyed by `objectId`. Every value has a non-nil `.object` with either `.map` or `.counter` populated; the | ||
| /// `accumulate` method enforces this invariant. | ||
| private var objectMessages: [String: InboundObjectMessage] | ||
|
|
||
| /// Creates an empty pool. | ||
| internal init() { | ||
| objectMessages = [:] | ||
| } | ||
|
|
||
| /// Accumulates object messages into the pool per RTO5f. | ||
| internal mutating func accumulate( | ||
lawrence-forooghian marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| _ objectMessages: [InboundObjectMessage], | ||
| logger: Logger, | ||
| ) { | ||
| for objectMessage in objectMessages { | ||
| accumulate(objectMessage, logger: logger) | ||
| } | ||
| } | ||
|
|
||
| /// Accumulates a single `ObjectMessage` into the pool per RTO5f. | ||
| private mutating func accumulate( | ||
| _ objectMessage: InboundObjectMessage, | ||
| logger: Logger, | ||
| ) { | ||
| // RTO5f3: Reject unsupported object types before pool lookup. Only messages whose `.object` has `.map` or `.counter` | ||
| // are stored, which callers of the iteration can rely on. | ||
| guard let object = objectMessage.object, object.map != nil || object.counter != nil else { | ||
| logger.log("Skipping unsupported object type during sync for objectId \(objectMessage.object?.objectId ?? "unknown")", level: .warn) | ||
| return | ||
| } | ||
|
|
||
| let objectId = object.objectId | ||
|
|
||
| if let existing = objectMessages[objectId] { | ||
| // RTO5f2: An entry already exists for this objectId (partial object state). | ||
| if object.map != nil { | ||
| // RTO5f2a: Incoming message has a map. | ||
| if object.tombstone { | ||
| // RTO5f2a1: Incoming tombstone is true — replace the entire entry. | ||
| objectMessages[objectId] = objectMessage | ||
| } else { | ||
| // RTO5f2a2: Merge map entries into the existing message. | ||
| var merged = existing | ||
| if let incomingEntries = object.map?.entries { | ||
| var mergedObject = merged.object! | ||
lawrence-forooghian marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| guard var mergedMap = mergedObject.map else { | ||
| // Not a specified scenario — the server won't send a map and a non-map for the same | ||
| // objectId in practice. Guard defensively rather than force-unwrapping. | ||
| logger.log("Existing entry for objectId \(objectId) is not a map; replacing with incoming message", level: .error) | ||
| objectMessages[objectId] = objectMessage | ||
| return | ||
| } | ||
| var mergedEntries = mergedMap.entries ?? [:] | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| mergedEntries.merge(incomingEntries) { _, new in new } | ||
| mergedMap.entries = mergedEntries | ||
| mergedObject.map = mergedMap | ||
| merged.object = mergedObject | ||
| } | ||
| objectMessages[objectId] = merged | ||
| } | ||
| } else { | ||
| // RTO5f2b: Incoming message has a counter — log error, skip. | ||
| logger.log("Received partial counter sync for objectId \(objectId); skipping", level: .error) | ||
| } | ||
| } else { | ||
| // RTO5f1: No entry exists for this objectId — store the message. | ||
| objectMessages[objectId] = objectMessage | ||
| } | ||
| } | ||
|
|
||
| // MARK: - Collection conformance | ||
|
|
||
| internal typealias Index = Dictionary<String, InboundObjectMessage>.Values.Index | ||
| internal typealias Element = InboundObjectMessage | ||
|
|
||
| internal var startIndex: Index { objectMessages.values.startIndex } | ||
| internal var endIndex: Index { objectMessages.values.endIndex } | ||
| internal func index(after i: Index) -> Index { objectMessages.values.index(after: i) } | ||
| internal subscript(position: Index) -> Element { objectMessages.values[position] } | ||
| } | ||
15 changes: 0 additions & 15 deletions
15
Sources/AblyLiveObjects/Internal/SyncObjectsPoolEntry.swift
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.