-
Notifications
You must be signed in to change notification settings - Fork 39
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 3 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -126,17 +126,30 @@ func (e RequestNotFoundErr) Error() string { | |
return "request not found" | ||
} | ||
|
||
// RemoteMissingBlockErr indicates that the remote peer was missing a block | ||
// in the selector requested. It is a non-terminal error in the error stream | ||
// MissingBlockErr indicates that the remote peer was missing a block | ||
// in the selector requested, and we also don't have it locally. | ||
// It is a non-terminal error in the error stream | ||
// for a request and does NOT cause a request to fail completely | ||
type RemoteMissingBlockErr struct { | ||
type MissingBlockErr struct { | ||
Link ipld.Link | ||
} | ||
|
||
func (e RemoteMissingBlockErr) Error() string { | ||
func (e MissingBlockErr) Error() string { | ||
return fmt.Sprintf("remote peer is missing block: %s", e.Link.String()) | ||
} | ||
|
||
// 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 | ||
} | ||
|
||
func (e RemoteIncorrectResponseError) Error() string { | ||
return fmt.Sprintf("next link %s in remote traversal does not match next link %s in local traversal, possible malicious responder", e.LocalLink, e.RemoteLink) | ||
} | ||
|
||
var ( | ||
// ErrExtensionAlreadyRegistered means a user extension can be registered only once | ||
ErrExtensionAlreadyRegistered = errors.New("extension already registered") | ||
|
@@ -223,6 +236,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) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -84,7 +84,7 @@ func TestMakeRequestToNetwork(t *testing.T) { | |
graphSync := td.GraphSyncHost1() | ||
|
||
blockChainLength := 100 | ||
blockChain := testutil.SetupBlockChain(ctx, t, td.persistence1, 100, blockChainLength) | ||
blockChain := testutil.SetupBlockChain(ctx, t, td.persistence2, 100, blockChainLength) | ||
|
||
requestCtx, requestCancel := context.WithCancel(ctx) | ||
defer requestCancel() | ||
|
@@ -109,6 +109,11 @@ func TestMakeRequestToNetwork(t *testing.T) { | |
require.True(t, found) | ||
require.Equal(t, td.extensionData, returnedData, "Failed to encode extension") | ||
|
||
builder := gsmsg.NewBuilder() | ||
builder.AddResponseCode(receivedRequest.ID(), graphsync.RequestRejected) | ||
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 do we need this now? is it because this test never needed to actually make a response and the previous version had all the blocks locally; but this new one puts the blocks on the remote but then tells the client to get lost? So we're simply testing the ability to make a network connection and have the most basic interaction here? 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. yea this test is from very far back in the early graphsync development days -- when I was just seeing if the protocol was generating the network traffic I expected. So previously, it yes loaded absolutely everything locally but we just wanted to make sure a request got made. Maybe the right move now is eliminate, since really, at this point, I'm pretty sure we can send network requests :P 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. eliminated |
||
response, err := builder.Build() | ||
require.NoError(t, err) | ||
td.gsnet2.SendMessage(ctx, td.host1.ID(), response) | ||
drain(graphSync) | ||
|
||
tracing := collectTracing(t) | ||
|
@@ -117,6 +122,7 @@ func TestMakeRequestToNetwork(t *testing.T) { | |
"request(0)->executeTask(0)", | ||
"request(0)->terminateRequest(0)", | ||
"message(0)->sendMessage(0)", | ||
"processResponses(0)", | ||
}, tracing.TracesToStrings()) | ||
|
||
// make sure the attributes are what we expect | ||
|
@@ -224,7 +230,7 @@ func TestRejectRequestsByDefault(t *testing.T) { | |
"request(0)->newRequest(0)", | ||
"request(0)->executeTask(0)", | ||
"request(0)->terminateRequest(0)", | ||
"processResponses(0)->loaderProcess(0)->cacheProcess(0)", | ||
"processResponses(0)", | ||
"processRequests(0)->transaction(0)->execute(0)->buildMessage(0)", | ||
"message(0)->sendMessage(0)", | ||
"message(1)->sendMessage(0)", | ||
|
@@ -278,8 +284,8 @@ func TestGraphsyncRoundTripRequestBudgetRequestor(t *testing.T) { | |
require.Contains(t, traceStrings, "request(0)->newRequest(0)") | ||
require.Contains(t, traceStrings, "request(0)->executeTask(0)") | ||
require.Contains(t, traceStrings, "request(0)->terminateRequest(0)") | ||
require.Contains(t, traceStrings, "processResponses(0)->loaderProcess(0)->cacheProcess(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
require.Contains(t, traceStrings, "processResponses(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
|
||
// has ErrBudgetExceeded exception recorded in the right place | ||
tracing.SingleExceptionEvent(t, "request(0)->executeTask(0)", "ErrBudgetExceeded", "traversal budget exceeded", true) | ||
|
@@ -327,8 +333,8 @@ func TestGraphsyncRoundTripRequestBudgetResponder(t *testing.T) { | |
require.Contains(t, traceStrings, "request(0)->newRequest(0)") | ||
require.Contains(t, traceStrings, "request(0)->executeTask(0)") | ||
require.Contains(t, traceStrings, "request(0)->terminateRequest(0)") | ||
require.Contains(t, traceStrings, "processResponses(0)->loaderProcess(0)->cacheProcess(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
require.Contains(t, traceStrings, "processResponses(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
|
||
// has ContextCancelError exception recorded in the right place | ||
// the requester gets a cancel, the responder gets a ErrBudgetExceeded | ||
|
@@ -411,27 +417,27 @@ func TestGraphsyncRoundTrip(t *testing.T) { | |
require.Contains(t, traceStrings, "request(0)->newRequest(0)") | ||
require.Contains(t, traceStrings, "request(0)->executeTask(0)") | ||
require.Contains(t, traceStrings, "request(0)->terminateRequest(0)") | ||
require.Contains(t, traceStrings, "processResponses(0)->loaderProcess(0)->cacheProcess(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
require.Contains(t, traceStrings, "processResponses(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
|
||
processUpdateSpan := tracing.FindSpanByTraceString("response(0)") | ||
require.Equal(t, int64(0), testutil.AttributeValueInTraceSpan(t, *processUpdateSpan, "priority").AsInt64()) | ||
require.Equal(t, []string{string(td.extensionName)}, testutil.AttributeValueInTraceSpan(t, *processUpdateSpan, "extensions").AsStringSlice()) | ||
|
||
// each verifyBlock span should link to a cacheProcess span that stored it | ||
|
||
cacheProcessSpans := tracing.FindSpans("cacheProcess") | ||
cacheProcessLinks := make(map[string]int64) | ||
processResponsesSpans := tracing.FindSpans("processResponses") | ||
processResponsesLinks := make(map[string]int64) | ||
verifyBlockSpans := tracing.FindSpans("verifyBlock") | ||
|
||
for _, verifyBlockSpan := range verifyBlockSpans { | ||
require.Len(t, verifyBlockSpan.Links, 1, "verifyBlock span should have one link") | ||
found := false | ||
for _, cacheProcessSpan := range cacheProcessSpans { | ||
sid := cacheProcessSpan.SpanContext.SpanID().String() | ||
for _, prcessResponseSpan := range processResponsesSpans { | ||
sid := prcessResponseSpan.SpanContext.SpanID().String() | ||
if verifyBlockSpan.Links[0].SpanContext.SpanID().String() == sid { | ||
found = true | ||
cacheProcessLinks[sid] = cacheProcessLinks[sid] + 1 | ||
processResponsesLinks[sid] = processResponsesLinks[sid] + 1 | ||
break | ||
} | ||
} | ||
|
@@ -440,9 +446,9 @@ func TestGraphsyncRoundTrip(t *testing.T) { | |
|
||
// each cacheProcess span should be linked to one verifyBlock span per block it stored | ||
|
||
for _, cacheProcessSpan := range cacheProcessSpans { | ||
blockCount := testutil.AttributeValueInTraceSpan(t, cacheProcessSpan, "blockCount").AsInt64() | ||
require.Equal(t, cacheProcessLinks[cacheProcessSpan.SpanContext.SpanID().String()], blockCount, "cacheProcess span should be linked to one verifyBlock span per block it processed") | ||
for _, processResponseSpan := range processResponsesSpans { | ||
blockCount := testutil.AttributeValueInTraceSpan(t, processResponseSpan, "blockCount").AsInt64() | ||
require.Equal(t, processResponsesLinks[processResponseSpan.SpanContext.SpanID().String()], blockCount, "cacheProcess span should be linked to one verifyBlock span per block it processed") | ||
} | ||
}) | ||
} | ||
|
@@ -510,8 +516,8 @@ func TestGraphsyncRoundTripPartial(t *testing.T) { | |
require.Contains(t, traceStrings, "request(0)->newRequest(0)") | ||
require.Contains(t, traceStrings, "request(0)->executeTask(0)") | ||
require.Contains(t, traceStrings, "request(0)->terminateRequest(0)") | ||
require.Contains(t, traceStrings, "processResponses(0)->loaderProcess(0)->cacheProcess(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
require.Contains(t, traceStrings, "processResponses(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
} | ||
|
||
func TestGraphsyncRoundTripIgnoreCids(t *testing.T) { | ||
|
@@ -744,8 +750,8 @@ func TestPauseResume(t *testing.T) { | |
require.Contains(t, traceStrings, "request(0)->newRequest(0)") | ||
require.Contains(t, traceStrings, "request(0)->executeTask(0)") | ||
require.Contains(t, traceStrings, "request(0)->terminateRequest(0)") | ||
require.Contains(t, traceStrings, "processResponses(0)->loaderProcess(0)->cacheProcess(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
require.Contains(t, traceStrings, "processResponses(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
|
||
// pause recorded | ||
tracing.SingleExceptionEvent(t, "response(0)->executeTask(0)", "github.com/ipfs/go-graphsync/responsemanager/hooks.ErrPaused", hooks.ErrPaused{}.Error(), false) | ||
|
@@ -827,8 +833,8 @@ func TestPauseResumeRequest(t *testing.T) { | |
require.Contains(t, traceStrings, "request(0)->executeTask(0)") | ||
require.Contains(t, traceStrings, "request(0)->executeTask(1)") | ||
require.Contains(t, traceStrings, "request(0)->terminateRequest(0)") | ||
require.Contains(t, traceStrings, "processResponses(0)->loaderProcess(0)->cacheProcess(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
require.Contains(t, traceStrings, "processResponses(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
|
||
// has ErrPaused exception recorded in the right place | ||
tracing.SingleExceptionEvent(t, "request(0)->executeTask(0)", "ErrPaused", hooks.ErrPaused{}.Error(), false) | ||
|
@@ -1115,8 +1121,8 @@ func TestNetworkDisconnect(t *testing.T) { | |
require.Contains(t, traceStrings, "request(0)->newRequest(0)") | ||
require.Contains(t, traceStrings, "request(0)->executeTask(0)") | ||
require.Contains(t, traceStrings, "request(0)->terminateRequest(0)") | ||
require.Contains(t, traceStrings, "processResponses(0)->loaderProcess(0)->cacheProcess(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
require.Contains(t, traceStrings, "processResponses(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
|
||
// has ContextCancelError exception recorded in the right place | ||
tracing.SingleExceptionEvent(t, "request(0)->executeTask(0)", "ContextCancelError", ipldutil.ContextCancelError{}.Error(), false) | ||
|
@@ -1256,8 +1262,8 @@ func TestGraphsyncRoundTripAlternatePersistenceAndNodes(t *testing.T) { | |
require.Contains(t, traceStrings, "request(1)->newRequest(0)") | ||
require.Contains(t, traceStrings, "request(1)->executeTask(0)") | ||
require.Contains(t, traceStrings, "request(1)->terminateRequest(0)") | ||
require.Contains(t, traceStrings, "processResponses(0)->loaderProcess(0)->cacheProcess(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(1)->verifyBlock(0)") // should have one of these per block (TODO: why request(1) and not (0)?) | ||
require.Contains(t, traceStrings, "processResponses(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(1)->verifyBlock(0)") // should have one of these per block (TODO: why request(1) and not (0)?) | ||
|
||
// TODO(rvagg): this is randomly either a SkipMe or a ipldutil.ContextCancelError; confirm this is sane | ||
// tracing.SingleExceptionEvent(t, "request(0)->newRequest(0)","request(0)->executeTask(0)", "SkipMe", traversal.SkipMe{}.Error(), true) | ||
|
@@ -1345,8 +1351,8 @@ func TestGraphsyncRoundTripMultipleAlternatePersistence(t *testing.T) { | |
require.Contains(t, traceStrings, "request(1)->newRequest(0)") | ||
require.Contains(t, traceStrings, "request(1)->executeTask(0)") | ||
require.Contains(t, traceStrings, "request(1)->terminateRequest(0)") | ||
require.Contains(t, traceStrings, "processResponses(0)->loaderProcess(0)->cacheProcess(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
require.Contains(t, traceStrings, "processResponses(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
} | ||
|
||
// TestRoundTripLargeBlocksSlowNetwork test verifies graphsync continues to work | ||
|
@@ -1600,8 +1606,8 @@ func TestUnixFSFetch(t *testing.T) { | |
require.Contains(t, traceStrings, "request(0)->newRequest(0)") | ||
require.Contains(t, traceStrings, "request(0)->executeTask(0)") | ||
require.Contains(t, traceStrings, "request(0)->terminateRequest(0)") | ||
require.Contains(t, traceStrings, "processResponses(0)->loaderProcess(0)->cacheProcess(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
require.Contains(t, traceStrings, "processResponses(0)") // should have one of these per response | ||
require.Contains(t, traceStrings, "request(0)->verifyBlock(0)") // should have one of these per block | ||
} | ||
|
||
func TestGraphsyncBlockListeners(t *testing.T) { | ||
|
@@ -1873,11 +1879,5 @@ func (r *receiver) Disconnected(p peer.ID) { | |
} | ||
|
||
func processResponsesTraces(t *testing.T, tracing *testutil.Collector, responseCount int) []string { | ||
traces := testutil.RepeatTraceStrings("processResponses({})->loaderProcess(0)->cacheProcess(0)", responseCount-1) | ||
finalStub := tracing.FindSpanByTraceString(fmt.Sprintf("processResponses(%d)->loaderProcess(0)", responseCount-1)) | ||
require.NotNil(t, finalStub) | ||
if len(testutil.AttributeValueInTraceSpan(t, *finalStub, "requestIDs").AsStringSlice()) == 0 { | ||
return append(traces, fmt.Sprintf("processResponses(%d)->loaderProcess(0)", responseCount-1)) | ||
} | ||
return append(traces, fmt.Sprintf("processResponses(%d)->loaderProcess(0)->cacheProcess(0)", responseCount-1)) | ||
return testutil.RepeatTraceStrings("processResponses({})", responseCount) | ||
} |
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.
why the rename? it's still for remotes and we have other
Remote*
errors like the one you introduced belowUh oh!
There was an error while loading. Please reload this page.
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.
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.