Documentation
¶
Overview ¶
Package retrieval provides state tracking for IPFS content retrieval operations. It enables detailed diagnostics about the retrieval process, including which stage failed (path resolution, provider discovery, connection, or block retrieval) and statistics about provider interactions. This information is particularly useful for debugging timeout errors and understanding retrieval performance.
Index ¶
- Constants
- func WrapWithState(ctx context.Context, err error) error
- type ErrorWithState
- type RetrievalPhase
- type State
- func (rs *State) AddFailedProvider(peerID peer.ID)
- func (rs *State) AddFoundProvider(peerID peer.ID)
- func (rs *State) GetFailedProviders() []peer.ID
- func (rs *State) GetFoundProviders() []peer.ID
- func (rs *State) GetPhase() RetrievalPhase
- func (rs *State) GetRootCID() cid.Cid
- func (rs *State) GetTerminalCID() cid.Cid
- func (rs *State) SetPhase(phase RetrievalPhase)
- func (rs *State) SetRootCID(c cid.Cid)
- func (rs *State) SetTerminalCID(c cid.Cid)
- func (rs *State) Summary() string
Constants ¶
const ContextKey contextKey = "boxo-retrieval-state"
ContextKey is the key used to store State in a context.Context. This can be used directly with context.WithValue if needed, though the ContextWithState and StateFromContext functions are preferred.
const MaxProvidersSampleSize = 3
MaxProvidersSampleSize limits the number of provider peer IDs (both found and failed) that are kept as a sample for diagnostic purposes. This prevents unbounded memory growth while still providing useful debugging information.
Variables ¶
This section is empty.
Functions ¶
func WrapWithState ¶
WrapWithState wraps an error with retrieval state from the context. It returns an *ErrorWithState that preserves the state for custom handling.
The error is ALWAYS wrapped if retrieval state exists in the context, because even "no providers found" is meaningful diagnostic information. If the error is already an *ErrorWithState, it returns it unchanged to avoid double-wrapping.
Example usage in a gateway or IPFS implementation:
func fetchBlock(ctx context.Context, cid cid.Cid) (blocks.Block, error) {
block, err := blockService.GetBlock(ctx, cid)
if err != nil {
// Wrap error with retrieval diagnostics if available
return nil, retrieval.WrapWithState(ctx, err)
}
return block, nil
}
Callers can then extract the state for custom handling:
var errWithState *retrieval.ErrorWithState
if errors.As(err, &errWithState) {
state := errWithState.State()
if state.ProvidersFound.Load() == 0 {
// Handle "content not in network" case specially
}
}
Types ¶
type ErrorWithState ¶
type ErrorWithState struct {
// contains filtered or unexported fields
}
ErrorWithState wraps an error with retrieval state information. It preserves the retrieval diagnostics for programmatic access while providing human-readable error messages.
The zero value is not useful; use WrapWithState to create instances.
func (*ErrorWithState) Error ¶
func (e *ErrorWithState) Error() string
Error returns the error message with retrieval diagnostics appended. Format: "original error: retrieval: diagnostic summary"
If err is nil, returns a generic message. If state is nil, returns just the underlying error message.
func (*ErrorWithState) State ¶
func (e *ErrorWithState) State() *State
State returns the retrieval state associated with this error. This allows callers to access detailed diagnostics for custom handling.
func (*ErrorWithState) Unwrap ¶
func (e *ErrorWithState) Unwrap() error
Unwrap returns the wrapped error, allowing errors.Is and errors.As to work with the underlying error.
type RetrievalPhase ¶
type RetrievalPhase int
RetrievalPhase represents the current phase of content retrieval. Phases progress monotonically - they can only move forward, never backward. This helps identify where in the retrieval process a timeout or failure occurred.
const ( // PhaseInitializing indicates the retrieval process has not yet started. PhaseInitializing RetrievalPhase = iota // PhasePathResolution indicates the system is resolving an IPFS path to determine // what content needs to be fetched (e.g., /ipfs/Qm.../path/to/file). PhasePathResolution // PhaseProviderDiscovery indicates the system is finding peers that have the content. PhaseProviderDiscovery // PhaseConnecting indicates the system is establishing connections to providers. PhaseConnecting // PhaseDataRetrieval indicates the system is transferring data to the client. PhaseDataRetrieval )
func (RetrievalPhase) String ¶
func (p RetrievalPhase) String() string
String returns a human-readable name for the retrieval phase.
type State ¶
type State struct {
// ProvidersFound tracks the number of providers discovered for the content.
ProvidersFound atomic.Int32
// ProvidersAttempted tracks the number of providers we tried to connect to.
ProvidersAttempted atomic.Int32
// ProvidersConnected tracks the number of providers successfully connected.
ProvidersConnected atomic.Int32
// contains filtered or unexported fields
}
State tracks diagnostic information about IPFS content retrieval operations. It is safe for concurrent use and maintains monotonic stage progression. Use ContextWithState to add tracking to a context, and StateFromContext to retrieve the state for updates or inspection
func ContextWithState ¶
ContextWithState ensures a State exists in the context. If the context already contains a State, it returns the existing one. Otherwise, it creates a new State and adds it to the context. This function is idempotent and safe to call multiple times.
Example:
ctx, retrievalState := retrieval.ContextWithState(ctx) // Use retrievalState to track progress retrievalState.SetStage(retrieval.StageProviderDiscovery)
func NewState ¶
func NewState() *State
NewState creates a new State initialized to PhaseInitializing. The returned state is safe for concurrent use.
func StateFromContext ¶
StateFromContext retrieves the State from the context. Returns nil if no State is present in the context. This function is typically used by subsystems to check if retrieval tracking is enabled and to update the state if it is.
Example:
if retrievalState := retrieval.StateFromContext(ctx); retrievalState != nil {
retrievalState.SetStage(retrieval.StageBlockRetrieval)
retrievalState.ProvidersFound.Add(1)
}
func (*State) AddFailedProvider ¶
AddFailedProvider records a provider peer ID that failed to deliver the requested content. This method is safe for concurrent use.
func (*State) AddFoundProvider ¶
AddFoundProvider records a provider peer ID that was discovered during provider search. This method is safe for concurrent use.
func (*State) GetFailedProviders ¶
GetFailedProviders returns a sample of failed providers (up to MaxProvidersSampleSize). This is not all providers, just the first few for diagnostic purposes.
func (*State) GetFoundProviders ¶
GetFoundProviders returns a sample of found providers (up to MaxProvidersSampleSize). This is not all providers, just the first few for diagnostic purposes.
func (*State) GetPhase ¶
func (rs *State) GetPhase() RetrievalPhase
GetPhase returns the current retrieval phase. This method is safe for concurrent use.
func (*State) GetRootCID ¶
GetRootCID returns the root CID (first CID in the path). This method is safe for concurrent use.
func (*State) GetTerminalCID ¶
GetTerminalCID returns the terminal CID (CID of terminating DAG entity). This method is safe for concurrent use.
func (*State) SetPhase ¶
func (rs *State) SetPhase(phase RetrievalPhase)
SetPhase updates the current retrieval phase to the given phase. The phase progression is monotonic - phases can only move forward, never backward. If the provided phase is less than or equal to the current phase, this is a no-op. This method is safe for concurrent use.
func (*State) SetRootCID ¶
SetRootCID sets the root CID (first CID in the path). This method is safe for concurrent use.
func (*State) SetTerminalCID ¶
SetTerminalCID sets the terminal CID (CID of terminating DAG entity). This method is safe for concurrent use.