-
Notifications
You must be signed in to change notification settings - Fork 38
Refactor async loading for simplicity and correctness #356
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
Changes from all commits
3bbc962
0178112
0818f67
6465a4f
de4f016
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
@startuml Request Execution | ||
participant "GraphSync\nTop Level\nInterface" as TLI | ||
participant RequestManager | ||
participant TaskQueue | ||
participant RequestExecutor as RE | ||
participant ReconciledLoader | ||
participant TraversalRecord | ||
participant Verifier | ||
participant LocalStorage | ||
participant Traverser | ||
participant Network | ||
|
||
== Initialization == | ||
|
||
TLI -> RequestManager ** : Setup | ||
TLI -> RE ** : Setup | ||
TLI -> TaskQueue ** : Setup | ||
|
||
== Executing A Request == | ||
|
||
par | ||
note over TLI : Request Initiation | ||
TLI -> RequestManager : New Request | ||
RequestManager -> RequestManager : Create Request Context | ||
RequestManager -> TaskQueue : Push Request | ||
else | ||
note over RE: Request Execution | ||
TaskQueue -> RE : Next Request\nTo Process | ||
RE -> RequestManager : Initiate request execution | ||
RequestManager -> Traverser ** : Create to manage selector traversal | ||
RequestManager -> ReconciledLoader ** : create to manage | ||
RequestManager -> RE : Traverser + ReconciledLoader | ||
note over RE: Local loading phase | ||
loop until traversal complete, request context cancelled, or missing block locally | ||
Traverser -> RE : Request to load blocks\nto perform traversal | ||
RE -> ReconciledLoader : Load next block | ||
ReconciledLoader -> LocalStorage : Load Block | ||
LocalStorage --> ReconciledLoader : Block or missing | ||
ReconciledLoader -> TraversalRecord : Record link traversal | ||
TraversalRecord --> ReconciledLoader | ||
ReconciledLoader --> RE : Block or missing | ||
opt block is present | ||
RE --> Traverser : Next block to load | ||
end | ||
end | ||
RE -> Network : Send Graphsync Request | ||
RE -> ReconciledLoader : remote online | ||
ReconciledLoader -> Verifier ** : Create new from traversal record | ||
ReconciledLoader -> RE | ||
note over RE: Remote loading phase | ||
loop until traversal complete, request context cancelled, or missing block locally | ||
Traverser -> RE : Request to load blocks\nto perform traversal | ||
RE -> ReconciledLoader : Load next block | ||
alt on missing path for remote | ||
ReconciledLoader -> LocalStorage : Load Block | ||
LocalStorage --> ReconciledLoader : Block or missing | ||
else | ||
loop until block loaded, missing, or error | ||
opt new remote responses | ||
alt verification not done | ||
ReconciledLoader -> Verifier : verify next response | ||
alt success | ||
Verifier --> ReconciledLoader : verified | ||
ReconciledLoader -> ReconciledLoader : wait for more responses | ||
else failure | ||
Verifier --> ReconciledLoader : error | ||
end | ||
else verification done | ||
alt next response matches current block load | ||
|
||
alt next response contains a block | ||
ReconciledLoader -> LocalStorage : store remote block | ||
LocalStorage --> ReconciledLoader | ||
ReconciledLoader -> ReconciledLoader : block laoded from remote | ||
else next response does not contain block | ||
opt next response is missing | ||
ReconciledLoader -> ReconciledLoader : record missing path | ||
end | ||
ReconciledLoader -> LocalStorage : load block | ||
LocalStorage --> ReconciledLoader : block or missing | ||
end | ||
else next response doesn not match | ||
ReconciledLoader -> ReconciledLoader : error | ||
end | ||
end | ||
end | ||
opt remote goes offline | ||
ReconciledLoader -> LocalStorage : load block | ||
LocalStorage --> ReconciledLoader : block or missing | ||
end | ||
end | ||
ReconciledLoader -> TraversalRecord : Record link traversal | ||
TraversalRecord --> ReconciledLoader | ||
ReconciledLoader --> RE : Block, missing or error | ||
RE -> Traverser : Next block to load | ||
end | ||
end | ||
else | ||
Network -> RequestManager : New Responses | ||
RequestManager -> ReconciledLoader : Ingest Responses | ||
end | ||
@enduml |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -127,14 +127,29 @@ func (e RequestNotFoundErr) Error() string { | |
} | ||
|
||
// RemoteMissingBlockErr indicates that the remote peer was missing a block | ||
// in the selector requested. It is a non-terminal error in the error stream | ||
// in the selector requested, and we also don't have it locally. | ||
// It is a -terminal error in the error stream | ||
// for a request and does NOT cause a request to fail completely | ||
type RemoteMissingBlockErr struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why the rename? it's still for remotes and we have other There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. technically it's now just a "missing block" -- missing both locally & remotely -- maybe a rename that breaks compatibility isn't worth it just to be super accurate. |
||
Link ipld.Link | ||
Path ipld.Path | ||
} | ||
|
||
func (e RemoteMissingBlockErr) Error() string { | ||
return fmt.Sprintf("remote peer is missing block: %s", e.Link.String()) | ||
return fmt.Sprintf("remote peer is missing block (%s) at path %s", e.Link.String(), e.Path) | ||
} | ||
|
||
// RemoteIncorrectResponseError indicates that the remote peer sent a response | ||
// to a traversal that did not correspond with the expected next link | ||
// in the selector traversal based on verification of data up to this point | ||
type RemoteIncorrectResponseError struct { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the path where this link mismatched occured might be useful context as well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
LocalLink ipld.Link | ||
RemoteLink ipld.Link | ||
Path ipld.Path | ||
} | ||
|
||
func (e RemoteIncorrectResponseError) Error() string { | ||
return fmt.Sprintf("expected link (%s) at path %s does not match link sent by remote (%s), possible malicious responder", e.LocalLink, e.Path, e.RemoteLink) | ||
} | ||
|
||
var ( | ||
|
@@ -223,6 +238,8 @@ type LinkMetadataIterator func(cid.Cid, LinkAction) | |
|
||
// LinkMetadata is used to access link metadata through an Iterator | ||
type LinkMetadata interface { | ||
// Length returns the number of metadata entries | ||
Length() int64 | ||
// Iterate steps over individual metadata one by one using the provided | ||
// callback | ||
Iterate(LinkMetadataIterator) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gets a bit dense in here; to the point where I wonder about the utility of the detail, but I think this looks right